• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

kcachegrind

  • sources
  • kde-4.14
  • kdesdk
  • kcachegrind
  • libcore
eventtype.cpp
Go to the documentation of this file.
1 /* This file is part of KCachegrind.
2  Copyright (C) 2002 - 2009 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
3 
4  KCachegrind is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public
6  License as published by the Free Software Foundation, version 2.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 #include "eventtype.h"
20 
21 #include <QRegExp>
22 #include <QDebug>
23 
24 #include "globalconfig.h"
25 
26 //---------------------------------------------------
27 // EventType
28 
29 QList<EventType*>* EventType::_knownTypes = 0;
30 
31 EventType::EventType(const QString& name, const QString& longName,
32  const QString& formula)
33 {
34  _name = name;
35  _longName = longName;
36  _formula = formula;
37  _isReal = formula.isEmpty();
38  _set = 0;
39  _realIndex = ProfileCostArray::InvalidIndex;
40  _parsed = false;
41  _inParsing = false;
42 
43  for (int i=0; i<ProfileCostArray::MaxRealIndex;i++)
44  _coefficient[i] = 0;
45 }
46 
47 void EventType::setFormula(const QString& formula)
48 {
49  _formula = formula;
50  _realIndex = ProfileCostArray::InvalidIndex;
51  _parsed = false;
52  _isReal = false;
53 }
54 
55 void EventType::setEventTypeSet(EventTypeSet* m)
56 {
57  _parsed = false;
58  _set = m;
59 }
60 
61 // setting the index to ProfileCostArray::MaxRealIndex makes it a
62 // real type with unspecified index
63 void EventType::setRealIndex(int i)
64 {
65  if (i<0 || i>ProfileCostArray::MaxRealIndex)
66  i=ProfileCostArray::InvalidIndex;
67 
68  _realIndex = i;
69  _formula = QString();
70  _isReal = true;
71 }
72 
73 // checks for existing types and sets coefficients
74 bool EventType::parseFormula()
75 {
76  if (isReal()) return true;
77  if (_parsed) return true;
78 
79  if (_inParsing) {
80  qDebug("TraceEventType::parseFormula: Recursion detected.");
81  return false;
82  }
83 
84  if (!_set) {
85  qDebug("TraceEventType::parseFormula: Container of this event type unknown!");
86  return false;
87  }
88 
89  _inParsing = true;
90 
91  for (int i=0; i<ProfileCostArray::MaxRealIndex;i++)
92  _coefficient[i] = 0;
93  _parsedFormula = QString();
94 
95  QRegExp rx( "((?:\\+|\\-)?)\\s*(\\d*)\\s*\\*?\\s*(\\w+)" );
96 
97  int factor, pos, found, matching;
98  QString costName;
99  EventType* eventType;
100 
101  found = 0; // how many types are referenced in formula
102  matching = 0; // how many types actually are defined in profile data
103  pos = 0;
104  while (1) {
105  pos = rx.indexIn(_formula, pos);
106  if (pos<0) break;
107  pos += rx.matchedLength();
108  if (rx.cap(0).isEmpty()) break;
109  found++;
110 
111  //qDebug("parseFormula: matched '%s','%s','%s'",
112  // qPrintable(rx.cap(1)), qPrintable(rx.cap(2)), qPrintable(rx.cap(3)));
113 
114  costName = rx.cap(3);
115  eventType = _set->type(costName);
116  if (!eventType) {
117  //qDebug("Cost type '%s': In formula cost '%s' unknown.",
118  // qPrintable(_name), qPrintable(costName));
119  continue;
120  }
121 
122  factor = (rx.cap(2).isEmpty()) ? 1 : rx.cap(2).toInt();
123  if (rx.cap(1) == "-") factor = -factor;
124  if (factor == 0) continue;
125 
126  matching++;
127 
128  if (!_parsedFormula.isEmpty()) {
129  _parsedFormula += QString(" %1 ").arg((factor>0) ? '+':'-');
130  }
131  else if (factor<0)
132  _parsedFormula += "- ";
133  if ((factor!=-1) && (factor!=1))
134  _parsedFormula += QString::number( (factor>0)?factor:-factor ) + ' ';
135  _parsedFormula += costName;
136 
137  if (eventType->isReal())
138  _coefficient[eventType->realIndex()] += factor;
139  else {
140  eventType->parseFormula();
141  for (int i=0; i<ProfileCostArray::MaxRealIndex;i++)
142  _coefficient[i] += factor * eventType->_coefficient[i];
143  }
144  }
145 
146  _inParsing = false;
147  if (found == 0) {
148  // empty formula
149  _parsedFormula = QString("0");
150  _parsed = true;
151  return true;
152  }
153  if (matching>0) {
154  _parsed = true;
155  return true;
156  }
157  return false;
158 }
159 
160 
161 QString EventType::parsedFormula()
162 {
163  if (isReal()) return QString();
164 
165  parseFormula();
166  return _parsedFormula;
167 }
168 
169 QString EventType::parsedRealFormula()
170 {
171  QString res;
172 
173  if (!parseFormula()) return res;
174 
175  for (int i=0; i<ProfileCostArray::MaxRealIndex;i++) {
176  int c = _coefficient[i];
177  if (c == 0) continue;
178 
179  if (!res.isEmpty()) {
180  res += ' ';
181  if (c>0) res += "+ ";
182  }
183  if (c<0) { res += "- "; c = -c; }
184  res += QString::number(c);
185 
186  EventType* t = _set->type(i);
187  if (!t) continue;
188 
189  if (!t->name().isEmpty())
190  res += QString(" * %1").arg(t->name());
191  }
192 
193  return res;
194 }
195 
196 SubCost EventType::subCost(ProfileCostArray* c)
197 {
198  if (_realIndex != ProfileCostArray::InvalidIndex)
199  return c->subCost(_realIndex);
200 
201  if (!_parsed) {
202  if (!parseFormula()) return 0;
203  }
204  SubCost res = 0;
205 
206  int rc = _set->realCount();
207  for (int i = 0;i<rc;i++)
208  if (_coefficient[i] != 0)
209  res += _coefficient[i] * c->subCost(i);
210 
211  return res;
212 }
213 
214 int EventType::histCost(ProfileCostArray* c, double total, double* hist)
215 {
216  if (total == 0.0) return 0;
217 
218  if (!_parsed) {
219  if (!parseFormula()) return 0;
220  }
221 
222  int rc = _set->realCount();
223  for (int i = 0;i<rc;i++) {
224  if (_coefficient[i] != 0)
225  hist[i] = _coefficient[i] * c->subCost(i) / total;
226  else
227  hist[i] = 0.0;
228  }
229 
230  return rc;
231 }
232 
233 
234 
235 
236 EventType* EventType::knownRealType(const QString& n)
237 {
238  if (!_knownTypes) return 0;
239 
240  foreach (EventType* t, *_knownTypes)
241  if (t->isReal() && (t->name() == n)) {
242  EventType* type = new EventType(*t);
243  return type;
244  }
245 
246  return 0;
247 }
248 
249 EventType* EventType::knownDerivedType(const QString& n)
250 {
251  if (!_knownTypes) return 0;
252 
253  foreach (EventType* t, *_knownTypes)
254  if (!t->isReal() && (t->name() == n)) {
255  EventType* type = new EventType(*t);
256  return type;
257  }
258 
259  return 0;
260 }
261 
262 // we take ownership
263 void EventType::add(EventType* t, bool overwriteExisting)
264 {
265  if (!t) return;
266 
267  t->setEventTypeSet(0);
268 
269  if (!_knownTypes)
270  _knownTypes = new QList<EventType*>;
271 
272  /* Already known? */
273  foreach (EventType* kt, *_knownTypes)
274  if (kt->name() == t->name()) {
275  if (overwriteExisting) {
276  // Overwrite old type
277  if (!t->longName().isEmpty() && (t->longName() != t->name()))
278  kt->setLongName(t->longName());
279  if (!t->formula().isEmpty())
280  kt->setFormula(t->formula());
281  }
282  delete t;
283  return;
284  }
285 
286  if (t->longName().isEmpty()) t->setLongName(t->name());
287  _knownTypes->append(t);
288 }
289 
290 
291 int EventType::knownTypeCount()
292 {
293  if (!_knownTypes) return 0;
294 
295  return _knownTypes->count();
296 }
297 
298 bool EventType::remove(const QString& n)
299 {
300  if (!_knownTypes) return false;
301 
302  foreach (EventType* t, *_knownTypes)
303  if (!t->isReal() && (t->name() == n)) {
304  _knownTypes->removeAll(t);
305  delete t;
306  return true;
307  }
308 
309  return false;
310 }
311 
312 EventType* EventType::knownType(int i)
313 {
314  if (!_knownTypes) return 0;
315  if (i<0 || i>=(int)_knownTypes->count()) return 0;
316 
317  return _knownTypes->at(i);
318 }
319 
320 
321 //---------------------------------------------------
322 // EventTypeSet
323 
324 EventTypeSet::EventTypeSet()
325 {
326  _realCount = 0;
327  _derivedCount = 0;
328  for (int i=0;i<ProfileCostArray::MaxRealIndex;i++) _real[i] = 0;
329  for (int i=0;i<ProfileCostArray::MaxRealIndex;i++) _derived[i] = 0;
330 }
331 
332 EventTypeSet::~EventTypeSet()
333 {
334  for (int i=0;i<ProfileCostArray::MaxRealIndex;i++)
335  if (_real[i]) delete _real[i];
336 
337  for (int i=0;i<ProfileCostArray::MaxRealIndex;i++)
338  if (_derived[i]) delete _derived[i];
339 }
340 
341 EventTypeMapping* EventTypeSet::createMapping(const QString& types)
342 {
343  // first check if there is enough space in the set
344  int newCount = 0;
345  int pos = 0, pos2, len = types.length();
346 
347  while (1) {
348  // skip space
349  while((pos<len) && types[pos].isSpace()) pos++;
350 
351  pos2 = pos;
352  while((pos2<len) && !types[pos2].isSpace()) pos2++;
353  if (pos2 == pos) break;
354 
355  if (realIndex(types.mid(pos,pos2-pos)) == ProfileCostArray::InvalidIndex)
356  newCount++;
357 
358  pos = pos2;
359  }
360 
361  if (newCount+_realCount > ProfileCostArray::MaxRealIndex) {
362  qDebug() << "EventTypeSet::createMapping: No space for "
363  << newCount << " cost entries.";
364  qDebug() << "Increase MaxRealIndexValue in libcore/costitem.h and recompile.";
365  return 0;
366  }
367 
368  EventTypeMapping* mapping = new EventTypeMapping(this);
369 
370  pos = 0;
371  while (1) {
372  // skip space
373  while((pos<len) && types[pos].isSpace()) pos++;
374 
375  pos2 = pos;
376  while((pos2<len) && !types[pos2].isSpace()) pos2++;
377  if (pos2 == pos) break;
378 
379  mapping->append(addReal(types.mid(pos,pos2-pos)));
380 
381  pos = pos2;
382  }
383 
384  return mapping;
385 }
386 
387 int EventTypeSet::addReal(const QString& t)
388 {
389  int index = realIndex(t);
390  if (index>=0) return index;
391 
392  EventType* ct = EventType::knownRealType(t);
393  if (!ct) ct = new EventType(t, t);
394 
395  // make it real
396  ct->setRealIndex();
397 
398  return add(ct);
399 }
400 
401 // add an event type to a set
402 // this transfers ownership of the type!
403 int EventTypeSet::add(EventType* et)
404 {
405  if (!et) return ProfileCostArray::InvalidIndex;
406 
407  et->setEventTypeSet(this);
408 
409  if (et->isReal()) {
410  if (_realCount >= ProfileCostArray::MaxRealIndex) {
411  qDebug("WARNING: Maximum for real event types reached (on adding '%s')",
412  qPrintable(et->name()));
413  return ProfileCostArray::InvalidIndex;
414  }
415  _real[_realCount] = et;
416  et->setRealIndex(_realCount);
417 
418  _realCount++;
419  return _realCount-1;
420  }
421 
422  if (_derivedCount >= ProfileCostArray::MaxRealIndex) {
423  qDebug("WARNING: Maximum for virtual event types reached (on adding '%s')",
424  qPrintable(et->name()));
425  return ProfileCostArray::InvalidIndex;
426  }
427  _derived[_derivedCount] = et;
428  _derivedCount++;
429  return _derivedCount-1;
430 }
431 
432 // we delete the type: t is invalid when returning true!
433 bool EventTypeSet::remove(EventType* t)
434 {
435  if (!t) return false;
436  if (t->set() != this) return false;
437 
438  // do not delete real types
439  if (t->isReal()) return false;
440 
441  int i;
442  for(i=0;i<_derivedCount;i++)
443  if (_derived[i] == t) break;
444 
445  // not found?
446  if (i == _derivedCount) return false;
447 
448  // delete known type with same name
449  EventType::remove(t->name());
450 
451  // delete this type
452  _derived[i] = 0;
453  delete t;
454  if (i+1 == _derivedCount) {
455  // we can reuse the last index
456  _derivedCount--;
457  }
458  return true;
459 }
460 
461 
462 EventType* EventTypeSet::realType(int t)
463 {
464  if (t<0 || t>=_realCount) return 0;
465  return _real[t];
466 }
467 
468 EventType* EventTypeSet::derivedType(int t)
469 {
470  if (t<0 || t>=_derivedCount) return 0;
471  return _derived[t];
472 }
473 
474 
475 EventType* EventTypeSet::type(int t)
476 {
477  if (t<0) return 0;
478  if (t<_realCount) return _real[t];
479 
480  t -= ProfileCostArray::MaxRealIndex;
481  if (t<0) return 0;
482  if (t<_derivedCount) return _derived[t];
483 
484  return 0;
485 }
486 
487 EventType* EventTypeSet::type(const QString& name)
488 {
489  for (int i=0;i<_realCount;i++)
490  if (_real[i] && (_real[i]->name() == name))
491  return _real[i];
492 
493  for (int i=0;i<_derivedCount;i++)
494  if (_derived[i] && (_derived[i]->name() == name))
495  return _derived[i];
496 
497  return 0;
498 }
499 
500 EventType* EventTypeSet::typeForLong(const QString& name)
501 {
502  for (int i=0;i<_realCount;i++)
503  if (_real[i] && (_real[i]->longName() == name))
504  return _real[i];
505 
506  for (int i=0;i<_derivedCount;i++)
507  if (_derived[i] && (_derived[i]->longName() == name))
508  return _derived[i];
509 
510  return 0;
511 }
512 
513 
514 int EventTypeSet::realIndex(const QString& name)
515 {
516  for (int i=0;i<_realCount;i++)
517  if (_real[i] && (_real[i]->name() == name))
518  return i;
519 
520  return ProfileCostArray::InvalidIndex;
521 }
522 
523 int EventTypeSet::index(const QString& name)
524 {
525  for (int i=0;i<_realCount;i++)
526  if (_real[i] && (_real[i]->name() == name))
527  return i;
528 
529  for (int i=0;i<_derivedCount;i++)
530  if (_derived[i] && (_derived[i]->name() == name))
531  return ProfileCostArray::MaxRealIndex + 1 + i;
532 
533  return ProfileCostArray::InvalidIndex;
534 }
535 
536 int EventTypeSet::addKnownDerivedTypes()
537 {
538  int addCount = 0;
539  int addDiff, i;
540  int knownCount = EventType::knownTypeCount();
541 
542  while (1) {
543  addDiff = 0;
544  for (i=0; i<knownCount; i++) {
545  EventType* t = EventType::knownType(i);
546  if (t->isReal()) continue;
547  if (index(t->name()) != ProfileCostArray::InvalidIndex) continue;
548  t->setEventTypeSet(this);
549  if (t->parseFormula()) {
550  addDiff++;
551  add(new EventType(t->name(), t->longName(), t->formula()));
552  }
553  t->setEventTypeSet(0);
554  }
555  if (addDiff == 0) break;
556  addCount += addDiff;
557  }
558  return addCount;
559 }
560 
561 
562 //---------------------------------------------------
563 // EventTypeMapping
564 
565 EventTypeMapping::EventTypeMapping(EventTypeSet* set)
566 {
567  _set = set;
568  clear();
569 }
570 
571 void EventTypeMapping::clear()
572 {
573  _count = 0;
574  _isIdentity = true;
575  _firstUnused = 0;
576  for(int i=0;i<ProfileCostArray::MaxRealIndex;i++) {
577  _realIndex[i] = ProfileCostArray::InvalidIndex;
578  _nextUnused[i] = i+1;
579  }
580 }
581 
582 int EventTypeMapping::maxRealIndex(int count)
583 {
584  if (count > _count) count = _count;
585  if (_isIdentity) return count-1;
586 
587  int maxIndex = -1;
588  for(int j=0; j<count; j++)
589  if (maxIndex < _realIndex[j])
590  maxIndex = _realIndex[j];
591  return maxIndex;
592 }
593 
594 bool EventTypeMapping::append(const QString& type, bool create)
595 {
596  if (!_set) return false;
597  int index = create ? _set->addReal(type) : _set->realIndex(type);
598 
599  return append(index);
600 }
601 
602 bool EventTypeMapping::append(int type)
603 {
604  if (!_set) return false;
605  if ((type<0) || (type >= _set->realCount())) return false;
606 
607  if ( _count >= ProfileCostArray::MaxRealIndex) return false;
608 
609  _realIndex[_count] = type;
610 
611  if (_isIdentity && (_count != type)) _isIdentity = false;
612  if (type == _firstUnused)
613  _firstUnused = _nextUnused[type];
614  for(int i=0;i<type;i++)
615  if (_nextUnused[i] == type)
616  _nextUnused[i]=_nextUnused[type];
617 
618  _count++;
619  return true;
620 }
EventTypeSet::realCount
int realCount()
Definition: eventtype.h:133
QRegExp::cap
QString cap(int nth) const
ProfileCostArray::subCost
SubCost subCost(EventType *)
Returns a sub cost.
Definition: costitem.cpp:591
globalconfig.h
EventType::EventType
EventType(const QString &name, const QString &longName=QString(), const QString &formula=QString())
is a short (non-localized) identifier for the cost type, e.g.
Definition: eventtype.cpp:31
EventType::setEventTypeSet
void setEventTypeSet(EventTypeSet *m)
Definition: eventtype.cpp:55
ProfileCostArray::MaxRealIndex
static const int MaxRealIndex
Definition: costitem.h:150
EventType::parsedFormula
QString parsedFormula()
Definition: eventtype.cpp:161
QList::at
const T & at(int i) const
EventType::setFormula
void setFormula(const QString &)
Definition: eventtype.cpp:47
eventtype.h
ProfileCostArray::InvalidIndex
static const int InvalidIndex
Definition: costitem.h:151
EventTypeSet::addKnownDerivedTypes
int addKnownDerivedTypes()
Adds all known derived event types that can be parsed.
Definition: eventtype.cpp:536
EventTypeSet::type
EventType * type(int)
Definition: eventtype.cpp:475
EventTypeMapping::clear
void clear()
Definition: eventtype.cpp:571
EventTypeMapping
A index list into a EventTypeSet.
Definition: eventtype.h:170
EventType
A cost type, e.g.
Definition: eventtype.h:43
EventType::knownDerivedType
static EventType * knownDerivedType(const QString &)
Definition: eventtype.cpp:249
EventTypeSet::typeForLong
EventType * typeForLong(const QString &)
Definition: eventtype.cpp:500
EventType::knownRealType
static EventType * knownRealType(const QString &)
Definition: eventtype.cpp:236
QRegExp::matchedLength
int matchedLength() const
QRegExp::indexIn
int indexIn(const QString &str, int offset, CaretMode caretMode) const
QRegExp
EventTypeMapping::set
EventTypeSet * set()
Definition: eventtype.h:179
ProfileCostArray
An array of basic cost metrics for a trace item.
Definition: costitem.h:144
QString::number
QString number(int n, int base)
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
EventType::parseFormula
bool parseFormula()
Definition: eventtype.cpp:74
EventTypeMapping::EventTypeMapping
EventTypeMapping(EventTypeSet *)
Definition: eventtype.cpp:565
EventType::parsedRealFormula
QString parsedRealFormula()
Definition: eventtype.cpp:169
QString::toInt
int toInt(bool *ok, int base) const
EventType::knownTypeCount
static int knownTypeCount()
Definition: eventtype.cpp:291
QString::isEmpty
bool isEmpty() const
QList::removeAll
int removeAll(const T &value)
EventType::formula
const QString & formula()
Definition: eventtype.h:67
EventTypeSet::remove
bool remove(EventType *)
Definition: eventtype.cpp:433
EventTypeMapping::maxRealIndex
int maxRealIndex(int count)
Get maximal real index for the first mapping indexes.
Definition: eventtype.cpp:582
QString
EventType::remove
static bool remove(const QString &)
Definition: eventtype.cpp:298
QList< EventType * >
EventType::isReal
bool isReal()
Definition: eventtype.h:70
EventTypeSet::addReal
int addReal(const QString &)
Definition: eventtype.cpp:387
EventTypeSet::add
int add(EventType *)
Definition: eventtype.cpp:403
EventType::subCost
SubCost subCost(ProfileCostArray *)
Definition: eventtype.cpp:196
EventTypeSet::createMapping
EventTypeMapping * createMapping(const QString &types)
Defines a mapping from indexes into a list of costs to real event types If is false...
Definition: eventtype.cpp:341
EventTypeSet::realIndex
int realIndex(const QString &)
Definition: eventtype.cpp:514
EventTypeSet::realType
EventType * realType(int)
Definition: eventtype.cpp:462
QString::mid
QString mid(int position, int n) const
EventType::knownType
static EventType * knownType(int)
Definition: eventtype.cpp:312
EventTypeSet::EventTypeSet
EventTypeSet()
Definition: eventtype.cpp:324
EventTypeSet::index
int index(const QString &)
Definition: eventtype.cpp:523
EventType::add
static void add(EventType *, bool overwriteExisting=true)
Definition: eventtype.cpp:263
SubCost
Cost event counter, simple wrapper around a 64bit entity.
Definition: subcost.h:32
EventTypeSet::~EventTypeSet
~EventTypeSet()
Definition: eventtype.cpp:332
QString::length
int length() const
EventType::longName
const QString & longName()
Definition: eventtype.h:66
EventTypeSet
A class for managing a set of event types.
Definition: eventtype.h:117
EventType::setRealIndex
void setRealIndex(int r=ProfileCostArray::MaxRealIndex)
Definition: eventtype.cpp:63
EventType::realIndex
int realIndex()
Definition: eventtype.h:69
EventType::setLongName
void setLongName(const QString &n)
Definition: eventtype.h:58
EventTypeSet::derivedType
EventType * derivedType(int)
Definition: eventtype.cpp:468
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
EventTypeMapping::append
bool append(const QString &, bool create=true)
Definition: eventtype.cpp:594
EventType::set
EventTypeSet * set()
Definition: eventtype.h:68
EventType::histCost
int histCost(ProfileCostArray *c, double total, double *hist)
Definition: eventtype.cpp:214
EventType::name
const QString & name()
Definition: eventtype.h:65
EventTypeMapping::count
int count()
Get number of used indexes.
Definition: eventtype.h:184
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:39:50 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kcachegrind

Skip menu "kcachegrind"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal