Experimental Physics and Industrial Control System
Dirk Zimoch has proposed merging ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0.
Commit message:
Make filters available for database links
Requested reviews:
EPICS Core Developers (epics-core)
For more details, see:
https://code.launchpad.net/~dirk.zimoch/epics-base/+git/epics-base/+merge/378968
--
Your team EPICS Core Developers is requested to review the proposed merge of ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0.
diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
index 19f6038..905cffe 100644
--- a/modules/database/src/ioc/db/dbAccess.c
+++ b/modules/database/src/ioc/db/dbAccess.c
@@ -1023,7 +1023,7 @@ static long dbPutFieldLink(DBADDR *paddr,
short dbrType, const void *pbuffer, long nRequest)
{
dbLinkInfo link_info;
- DBADDR *pdbaddr = NULL;
+ dbChannel *chan = NULL;
dbCommon *precord = paddr->precord;
dbCommon *lockrecs[2];
dbLocker locker;
@@ -1061,16 +1061,11 @@ static long dbPutFieldLink(DBADDR *paddr,
if (link_info.ltype == PV_LINK &&
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
- DBADDR tempaddr;
-
- if (dbNameToAddr(link_info.target, &tempaddr)==0) {
- /* This will become a DB link. */
- pdbaddr = malloc(sizeof(*pdbaddr));
- if (!pdbaddr) {
- status = S_db_noMemory;
- goto cleanup;
- }
- *pdbaddr = tempaddr; /* struct copy */
+ chan = dbChannelCreate(link_info.target);
+ if (chan && dbChannelOpen(chan) != 0) {
+ errlogPrintf("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
+ precord->name, pfldDes->name, link_info.target);
+ goto cleanup;
}
}
@@ -1079,7 +1074,7 @@ static long dbPutFieldLink(DBADDR *paddr,
memset(&locker, 0, sizeof(locker));
lockrecs[0] = precord;
- lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL;
+ lockrecs[1] = chan ? dbChannelRecord(chan) : NULL;
dbLockerPrepare(&locker, lockrecs, 2);
dbScanLockMany(&locker);
@@ -1167,7 +1162,8 @@ static long dbPutFieldLink(DBADDR *paddr,
case PV_LINK:
case CONSTANT:
case JSON_LINK:
- dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr);
+ dbAddLink(&locker, plink, pfldDes->field_type, chan);
+ chan = NULL; /* don't clean it up */
break;
case DB_LINK:
@@ -1197,6 +1193,8 @@ unlock:
dbScanUnlockMany(&locker);
dbLockerFinalize(&locker);
cleanup:
+ if (chan)
+ dbChannelDelete(chan);
free(link_info.target);
return status;
}
diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c
index f2cb0c5..4d38185 100644
--- a/modules/database/src/ioc/db/dbDbLink.c
+++ b/modules/database/src/ioc/db/dbDbLink.c
@@ -60,6 +60,7 @@
#include "dbConvertFast.h"
#include "dbConvert.h"
#include "db_field_log.h"
+#include "db_access_routines.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "dbLockPvt.h"
@@ -73,7 +74,7 @@
#include "recSup.h"
#include "special.h"
#include "dbDbLink.h"
-
+#include "dbChannel.h"
/***************************** Database Links *****************************/
@@ -82,45 +83,63 @@ static lset dbDb_lset;
static long processTarget(dbCommon *psrc, dbCommon *pdst);
+#define linkChannel(plink) ((dbChannel *) (plink)->value.pv_link.pvt)
+
long dbDbInitLink(struct link *plink, short dbfType)
{
- DBADDR dbaddr;
long status;
- DBADDR *pdbAddr;
+ dbChannel *chan;
+ dbCommon *precord;
- status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
+ chan = dbChannelCreate(plink->value.pv_link.pvname);
+ if (!chan)
+ return S_db_notFound;
+ status = dbChannelOpen(chan);
if (status)
return status;
+ precord = dbChannelRecord(chan);
+
+ if (dbChannelFinalElements(chan) < 1) {
+ errlogPrintf("Warning: %s.%s=%s has %ld elements. This will not work.\n",
+ plink->precord->name, dbLinkFieldName(plink),
+ dbChannelName(chan), dbChannelFinalElements(chan));
+ }
+
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
- pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
- *pdbAddr = dbaddr; /* structure copy */
- plink->value.pv_link.pvt = pdbAddr;
- ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode);
+ plink->value.pv_link.pvt = chan;
+ ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode);
/* merging into the same lockset is deferred to the caller.
* cf. initPVLinks()
*/
- dbLockSetMerge(NULL, plink->precord, dbaddr.precord);
- assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet);
+ dbLockSetMerge(NULL, plink->precord, precord);
+ assert(plink->precord->lset->plockSet == precord->lset->plockSet);
return 0;
}
void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
- DBADDR *ptarget)
+ dbChannel *chan)
{
+ if (dbChannelFinalElements(chan) < 1) {
+ errlogPrintf("Warning: %s.%s=%s has %ld elements. This will not work.\n",
+ plink->precord->name, dbLinkFieldName(plink),
+ dbChannelName(chan), dbChannelFinalElements(chan));
+ }
+
plink->lset = &dbDb_lset;
plink->type = DB_LINK;
- plink->value.pv_link.pvt = ptarget;
- ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode);
+ plink->value.pv_link.pvt = chan;
+ ellAdd(&dbChannelRecord(chan)->bklnk, &plink->value.pv_link.backlinknode);
/* target record is already locked in dbPutFieldLink() */
- dbLockSetMerge(locker, plink->precord, ptarget->precord);
+ dbLockSetMerge(locker, plink->precord, dbChannelRecord(chan));
}
static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
{
- DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
plink->type = PV_LINK;
@@ -130,10 +149,10 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink)
plink->value.pv_link.getCvt = 0;
plink->value.pv_link.pvlMask = 0;
plink->value.pv_link.lastGetdbrType = 0;
- ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode);
- dbLockSetSplit(locker, plink->precord, pdbAddr->precord);
+ ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode);
+ dbLockSetSplit(locker, plink->precord, precord);
}
- free(pdbAddr);
+ dbChannelDelete(chan);
}
static int dbDbIsConnected(const struct link *plink)
@@ -143,16 +162,14 @@ static int dbDbIsConnected(const struct link *plink)
static int dbDbGetDBFtype(const struct link *plink)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- return paddr->field_type;
+ dbChannel *chan = linkChannel(plink);
+ return dbChannelFinalFieldType(chan);
}
static long dbDbGetElements(const struct link *plink, long *nelements)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *nelements = paddr->no_elements;
+ dbChannel *chan = linkChannel(plink);
+ *nelements = dbChannelFinalElements(chan);
return 0;
}
@@ -160,30 +177,48 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
long *pnRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
- DBADDR *paddr = ppv_link->pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
dbCommon *precord = plink->precord;
long status;
/* scan passive records if link is process passive */
if (ppv_link->pvlMask & pvlOptPP) {
- status = dbScanPassive(precord, paddr->precord);
+ status = dbScanPassive(precord, dbChannelRecord(chan));
if (status)
return status;
}
- if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ /* If filters are involved in a read, create field log and run filters */
+ if (ellCount(&chan->filters)) {
+ db_field_log *pfl;
+ long options = 0;
+
+ if (dbChannelFinalElements(chan) < 1)
+ {
+ recGblSetSevr(precord, LINK_ALARM, UDF_ALARM);
+ return S_db_badField;
+ }
+ pfl = db_create_read_log(chan);
+ if (pfl) {
+ pfl = dbChannelRunPreChain(chan, pfl);
+ pfl = dbChannelRunPostChain(chan, pfl);
+ status = dbChannelGet(chan, dbrType, pbuffer, &options, pnRequest, pfl);
+ db_delete_field_log(pfl);
+ }
+ } else if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) {
+ status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
} else {
- unsigned short dbfType = paddr->field_type;
+ unsigned short dbfType = dbChannelFinalFieldType(chan);
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
return S_db_badDbrtype;
- if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1)
- && paddr->special != SPC_DBADDR
- && paddr->special != SPC_ATTRIBUTE) {
+ if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1)
+ && dbChannelSpecial(chan) != SPC_DBADDR
+ && dbChannelSpecial(chan) != SPC_ATTRIBUTE) {
ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType];
- status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr);
+ status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr);
} else {
ppv_link->getCvt = NULL;
status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL);
@@ -191,16 +226,18 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
ppv_link->lastGetdbrType = dbrType;
}
- if (!status && precord != paddr->precord)
+ if (!status && precord != dbChannelRecord(chan))
recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode,
- plink->precord, paddr->precord->stat, paddr->precord->sevr);
+ plink->precord,
+ dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr);
return status;
}
static long dbDbGetControlLimits(const struct link *plink, double *low,
double *high)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRctrlDouble
double value;
@@ -221,7 +258,8 @@ static long dbDbGetControlLimits(const struct link *plink, double *low,
static long dbDbGetGraphicLimits(const struct link *plink, double *low,
double *high)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRgrDouble
double value;
@@ -242,7 +280,8 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low,
static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
double *low, double *high, double *hihi)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRalDouble
double value;
@@ -264,7 +303,8 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo,
static long dbDbGetPrecision(const struct link *plink, short *precision)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRprecision
double value;
@@ -283,7 +323,8 @@ static long dbDbGetPrecision(const struct link *plink, short *precision)
static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
+ dbChannel *chan = linkChannel(plink);
+ DBADDR *paddr = &chan->addr;
struct buffer {
DBRunits
double value;
@@ -303,20 +344,20 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize)
static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status,
epicsEnum16 *severity)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
if (status)
- *status = paddr->precord->stat;
+ *status = precord->stat;
if (severity)
- *severity = paddr->precord->sevr;
+ *severity = precord->sevr;
return 0;
}
static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp)
{
- DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt;
-
- *pstamp = paddr->precord->time;
+ dbChannel *chan = linkChannel(plink);
+ dbCommon *precord = dbChannelRecord(chan);
+ *pstamp = precord->time;
return 0;
}
@@ -324,9 +365,10 @@ static long dbDbPutValue(struct link *plink, short dbrType,
const void *pbuffer, long nRequest)
{
struct pv_link *ppv_link = &plink->value.pv_link;
+ dbChannel *chan = linkChannel(plink);
struct dbCommon *psrce = plink->precord;
- DBADDR *paddr = (DBADDR *) ppv_link->pvt;
- dbCommon *pdest = paddr->precord;
+ DBADDR *paddr = &chan->addr;
+ dbCommon *pdest = dbChannelRecord(chan);
long status = dbPut(paddr, dbrType, pbuffer, nRequest);
recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta,
@@ -334,7 +376,7 @@ static long dbDbPutValue(struct link *plink, short dbrType,
if (status)
return status;
- if (paddr->pfield == (void *) &pdest->proc ||
+ if (dbChannelField(chan) == (void *) &pdest->proc ||
(ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) {
status = processTarget(psrce, pdest);
}
@@ -345,9 +387,8 @@ static long dbDbPutValue(struct link *plink, short dbrType,
static void dbDbScanFwdLink(struct link *plink)
{
dbCommon *precord = plink->precord;
- dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt;
-
- dbScanPassive(precord, paddr->precord);
+ dbChannel *chan = linkChannel(plink);
+ dbScanPassive(precord, dbChannelRecord(chan));
}
static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv)
diff --git a/modules/database/src/ioc/db/dbDbLink.h b/modules/database/src/ioc/db/dbDbLink.h
index c367720..27972d8 100644
--- a/modules/database/src/ioc/db/dbDbLink.h
+++ b/modules/database/src/ioc/db/dbDbLink.h
@@ -26,7 +26,7 @@ struct dbLocker;
epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink,
- short dbfType, DBADDR *ptarget);
+ short dbfType, dbChannel *ptarget);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbLink.c b/modules/database/src/ioc/db/dbLink.c
index 7c37058..aa72dc8 100644
--- a/modules/database/src/ioc/db/dbLink.c
+++ b/modules/database/src/ioc/db/dbLink.c
@@ -143,7 +143,7 @@ void dbInitLink(struct link *plink, short dbfType)
}
void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType,
- DBADDR *ptarget)
+ dbChannel *ptarget)
{
struct dbCommon *precord = plink->precord;
diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h
index 94e1f32..4255a56 100644
--- a/modules/database/src/ioc/db/dbLink.h
+++ b/modules/database/src/ioc/db/dbLink.h
@@ -20,6 +20,7 @@
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAddr.h"
+#include "dbChannel.h"
#ifdef __cplusplus
extern "C" {
@@ -368,7 +369,7 @@ epicsShareFunc const char * dbLinkFieldName(const struct link *plink);
epicsShareFunc void dbInitLink(struct link *plink, short dbfType);
epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink,
- short dbfType, DBADDR *ptarget);
+ short dbfType, dbChannel *ptarget);
epicsShareFunc void dbLinkOpen(struct link *plink);
epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink);
diff --git a/modules/database/src/ioc/db/dbLock.c b/modules/database/src/ioc/db/dbLock.c
index 8df755b..19cb1c0 100644
--- a/modules/database/src/ioc/db/dbLock.c
+++ b/modules/database/src/ioc/db/dbLock.c
@@ -743,14 +743,14 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond)
for(i=0; i<rtype->no_links; i++) {
dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]];
DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset);
- DBADDR *ptarget;
+ dbChannel *chan;
lockRecord *lr;
if(plink->type!=DB_LINK)
continue;
- ptarget = plink->value.pv_link.pvt;
- lr = ptarget->precord->lset;
+ chan = plink->value.pv_link.pvt;
+ lr = dbChannelRecord(chan)->lset;
assert(lr);
if(lr->precord==pfirst) {
- Replies:
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 mdavidsaver via Core-talk
- [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 noreply--- via Core-talk
- Navigate by Date:
- Prev:
Build failed: epics-base-test base-7.0-33 AppVeyor via Core-talk
- Next:
Build failed: epics-base base-reuseport-395 AppVeyor via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Build failed: epics-base-test base-7.0-33 AppVeyor via Core-talk
- Next:
Re: [Merge] ~dirk.zimoch/epics-base:dbChannelForDBLinks into epics-base:7.0 Dirk Zimoch via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024