SlideShare a Scribd company logo
Improving Performance and Flexibility
of Content Listings Using Criteria API
Nils Breunese
Public Broadcaster since 1926 The Netherlands
Online since 1994 Open-source CMS released in 1997
Using Magnolia since 2010 Still migrating websites
Tens of thousands of pages Multiple sites like that
Overview pages Lots of them
Thanks for the warning… Even 10 seconds would be way too long
WARN info.magnolia.module.cache.filter.CacheFilter
-- The following URL took longer than 10 seconds
(63969 ms) to render. This might cause timeout
exceptions on other requests to the same URI.
Overview models Standard Templating Kit
Tracking back from the template newsOverview.ftl
(...)
[#assign pager = model.pager]

[#assign newsList = cmsfn.asContentMapList(pager.pageItems)!]
(...)
Constructing the pager AbstractItemListModel
public STKPager getPager() throws RepositoryException {

(...)

return new STKPager(currentPageLink, getItems(), content);

}
Four step pipeline AbstractItemListModel
public Collection<Node> getItems() throws RepositoryException {

List<Node> itemsList = search();



this.filter(itemsList);

this.sort(itemsList);

itemsList = this.shrink(itemsList);



return itemsList;

}
1
2
3
4
Step 1a: Constructing the query TemplateCategoryUtil
public static List<Node> getContentListByTemplateNames(...) {
(...)
StringBuffer sql = new StringBuffer(
"select * from nt:base where jcr:path like '"
+ path + "/%'");
(...add 'mgnl:template=' clauses...)
(...add 'ORDER BY' clauses...)

return getWrappedNodesFromQuery(sql.toString(),
repository, maxResultSize);
} maxResultSize == Integer.MAX_VALUE
Step 1b: Executing the query TemplateCategoryUtil
public static List<Node> getContentListByTemplateNames(...) {
(...)

NodeIterator items = QueryUtil.search(
repository,
sql.toString(),
Query.SQL,
NodeTypes.Content.NAME);
}
Step 2: Filtering the item list STKDateContentUtil
public static void filterDateContentList(...) {

CollectionUtils.filter(itemsList, new Predicate() {

@Override

public boolean evaluate(Object object) {

(...)
return date.after(minDate) && date.before(maxDate);

}

});

}
Step 3: Time to sort STKDateContentUtil
public static void sortDateContentList(...) {

Collections.sort(itemsList, new Comparator<Node>() {

@Override

public int compare(Node c1, Node c2) {

(...)

if (StringUtils.equals(sortDirection, ASCENDING)) {

return date2.compareTo(date1);

}

return date1.compareTo(date2);

}

});

}
Step 4: Shrinking the list STKTemplatingFunctions
public List<Node> cutList(List<Node> itemsList, final int maxResults) {

if (itemsList.size() > maxResults) {

return itemsList.subList(0, maxResults);

}

return itemsList;

}
NewsOverviewModel passes Integer.MAX_VALUE,
so shrink does effectively nothing in this case
Step 5: Get the items from the pager STKPager
public Collection getPageItems() {



Collection subList = items;

int offset = getOffset();

if (count > 0) {

int limit = maxResultsPerPage + offset;

if (items.size() < limit) {

limit = count;

}

subList = ((List) items).subList(offset, limit);



}

return subList;

}
maxResultsPerPage is
typically something like 20
When this becomes a problem We have multiple sites like this
select * from nt:base
where jcr:path like '/siteX/news/%' AND
mgnl:template = 'standard-templating-kit:pages/stkNews'
20000 pages under website:/siteX/news
Four step pipeline returns STKPager with 20000 items (page nodes)
[#assign model.pager]
[#assign newsList = cmsfn.asContentMapList(pager.pageItems)!]
STKPager returns list with 20 page nodes
19980 Node objects created, but not rendered
A query could do all steps at once JCR queries are pretty flexible
Everything in a single JCR query Only 20 nodes returned
SELECT * FROM nt:base
WHERE jcr:path LIKE '/siteX/news/%' AND
mgnl:template = 'standard-templating-kit:pages/stkNews'
AND jcr:created < cast('2016-06-07T00:00:00.000Z' AS DATE)
ORDER BY date ASCENDING
LIMIT 20 OFFSET 20
Search
Filter
Sort
Paging
Criteria API For those familiar with Hibernate/JPA
Criteria criteria = JCRCriteriaFactory.createCriteria()

.setBasePath("/siteX/news")

.add(Restrictions.eq(
"@mgnl:template", "standard-templating-kit:pages/stkNews"))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))

.addOrder(Order.asc("date"))

.setPaging(20, 1);


ResultIterator<...> items = criteria.execute(session).getItems();
Sort
Paging
Filter
Search
Criteria API for Magnolia CMS Magnolia module by Openmind
jcr-criteria https://github.com/vpro/jcr-criteria
Custom pager Only a single page worth of items
public class VtkPager<T> extends STKPager {


private final List<? extends T> items;
private final int pageSize;

private final int count;



(...)



@Override

public List<? extends T> getPageItems() {

return items;

}
}
Use it in your model classes VtkContentListModel (vpro)
public abstract class VtkContentListModel ... {



protected final VtkPager<ContentMap> pager;



@Override

public String execute() {

pager = createPager();

return super.execute();

}



protected abstract VtkPager<T> createPager();
(...)
}
Concrete Example VtkNewsOverviewModel (vpro)
@Override

protected VtkPager<Node> createPager() {
(...)

AdvancedResult result = JCRCriteriaFactory.createCriteria()

.setBasePath(path)

.add(Restrictions.in("@mgnl:template", templates))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
.addOrder(Order.asc("date"))
.setPaging(itemsPerPage, pageNumberStartingFromOne)
.execute(session);

List<Node> items = new ArrayList<>();

for (AdvancedResultItem item : result.getItems()) {

items.add(item.getJCRNode());

}



int count = result.getTotalSize();



return new VtkPager<>(link, items, content, itemsPerPage, count);
}
Still this. Was it all for nothing? :o(
WARN info.magnolia.module.cache.filter.CacheFilter
-- The following URL took longer than 10 seconds
(63969 ms) to render. This might cause timeout
exceptions on other requests to the same URI.
Example VtkNewsOverviewModel (vpro)
@Override

protected VtkPager<Node> createPager() {
(...)

AdvancedResult result = JCRCriteriaFactory.createCriteria()

.setBasePath(path)

.add(Restrictions.in("@mgnl:template", templates))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
.addOrder(Order.asc("date"))
.setPaging(itemsPerPage, pageNumberStartingFromOne)
.execute(session);

List<Node> items = new ArrayList<>();

for (AdvancedResultItem item : result.getItems()) {

items.add(item.getJCRNode());

}



int count = result.getTotalSize();



return new VtkPager<>(link, items, content, itemsPerPage, count);
}
This call takes 10-60+ seconds!
AdvancedResultImpl (jcr-criteria)
@Override

public int getTotalSize() {

if (totalResults == null) {

int queryTotalSize = -1;

try { // jcrQueryResult instanceof JackrabbitQueryResult) {

Method m = jcrQueryResult.getClass().getMethod("getTotalSize");

queryTotalSize = (int) m.invoke(jcrQueryResult);

} catch (InvocationTargetException | IllegalAccessException e) {

LOG.error(e.getMessage(), e);

} catch (NoSuchMethodException e) {



}

if (queryTotalSize == -1 && (itemsPerPage == 0 || applyLocalPaging)) {

try {

totalResults = (int) jcrQueryResult.getNodes().getSize();

} catch (RepositoryException e) {

// ignore, the standard total size will be returned

}

}



if (queryTotalSize == -1) {

totalResults = queryCounter.getAsInt();

} else {

totalResults = queryTotalSize;



}

}

return totalResults;

}
We end up here
jackrabbit-core 2.8.0
protected void getResults(long size) throws RepositoryException {

(...)

result = executeQuery(maxResultSize); // Lucene query
(...)
// Doesn’t use result.getSize(), call collectScoreNodes(...)
}
private void collectScoreNodes(...) {

while (collector.size() < maxResults) {

ScoreNode[] sn = hits.nextScoreNodes();
(...)

// check access

if (isAccessGranted(sn)) {

collector.add(sn);

} else {

invalid++;

}

}

} QueryResultImpl
It used to be fast! https://issues.apache.org/jira/browse/JCR-3858
jackrabbit-core 2.10.0+
protected void getResults(long size) throws RepositoryException {
(...)
if (sizeEstimate) {

numResults = result.getSize(); // Use count from Lucene



} else {

// do things the Jackrabbit 2.8.0 way

(...)

}
(...)
}
QueryResultImpl
Enable Jackrabbit’s 'sizeEstimate' Jackrabbit 2.10+
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
(...)
<param name="sizeEstimate" value="true"/>
</SearchIndex>
Rendering times down to 1-2 seconds Bingo
Time for questions
Anyone?
Feel free to contact me
Nils Breunese

@breun

n.breunese@vpro.nl

More Related Content

PDF
Do something useful in Apps Script 5. Get your analytics pageviews to a sprea...
PDF
Do something in 5 with gas 3-simple invoicing app
PPTX
Google apps script database abstraction exposed version
PDF
Do something in 5 with gas 4- Get your analytics profiles to a spreadsheet
PDF
Do something in 5 minutes with gas 1-use spreadsheet as database
PDF
JavaScript client API for Google Apps Script API primer
PPTX
MongoDB: Comparing WiredTiger In-Memory Engine to Redis
PDF
Presto in Treasure Data
Do something useful in Apps Script 5. Get your analytics pageviews to a sprea...
Do something in 5 with gas 3-simple invoicing app
Google apps script database abstraction exposed version
Do something in 5 with gas 4- Get your analytics profiles to a spreadsheet
Do something in 5 minutes with gas 1-use spreadsheet as database
JavaScript client API for Google Apps Script API primer
MongoDB: Comparing WiredTiger In-Memory Engine to Redis
Presto in Treasure Data

What's hot (20)

PPTX
MongoDB Chunks - Distribution, Splitting, and Merging
PPTX
Dbabstraction
PPTX
Google cloud datastore driver for Google Apps Script DB abstraction
PDF
Lab1-DB-Cassandra
KEY
Python Development (MongoSF)
PPTX
MongoDB - Aggregation Pipeline
PPTX
Goa tutorial
PPTX
MongoDB - Sharded Cluster Tutorial
PDF
Do something in 5 with gas 8-copy between databases
PPTX
Whats New for WPF in .NET 4.5
PDF
The Ring programming language version 1.5.4 book - Part 40 of 185
PPTX
SenchaCon 2016: The Once and Future Grid - Nige White
PDF
Taming the beast - how to tame React & GraphQL, one error at a time
PDF
Using MongoDB and Python
PDF
Assist9 bmis
PDF
Lazy evaluation drupal camp moscow 2014
PPTX
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
PDF
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
PDF
Managing Data and Operation Distribution In MongoDB
PDF
Store and Process Big Data with Hadoop and Cassandra
MongoDB Chunks - Distribution, Splitting, and Merging
Dbabstraction
Google cloud datastore driver for Google Apps Script DB abstraction
Lab1-DB-Cassandra
Python Development (MongoSF)
MongoDB - Aggregation Pipeline
Goa tutorial
MongoDB - Sharded Cluster Tutorial
Do something in 5 with gas 8-copy between databases
Whats New for WPF in .NET 4.5
The Ring programming language version 1.5.4 book - Part 40 of 185
SenchaCon 2016: The Once and Future Grid - Nige White
Taming the beast - how to tame React & GraphQL, one error at a time
Using MongoDB and Python
Assist9 bmis
Lazy evaluation drupal camp moscow 2014
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Managing Data and Operation Distribution In MongoDB
Store and Process Big Data with Hadoop and Cassandra
Ad

More from Nils Breunese (6)

PDF
Kotlin: a better Java
PDF
NLJUG J-Fall 2011
KEY
NLJUG J-Fall 2011
KEY
HTTP API for Free? Check out CouchDB
KEY
Website-tool: CMS of Framework
PDF
WSO2 Mashup Server
Kotlin: a better Java
NLJUG J-Fall 2011
NLJUG J-Fall 2011
HTTP API for Free? Check out CouchDB
Website-tool: CMS of Framework
WSO2 Mashup Server
Ad

Recently uploaded (20)

PPTX
Essential Infomation Tech presentation.pptx
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Transform Your Business with a Software ERP System
PDF
Understanding Forklifts - TECH EHS Solution
PDF
AI in Product Development-omnex systems
PPTX
L1 - Introduction to python Backend.pptx
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
ai tools demonstartion for schools and inter college
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Essential Infomation Tech presentation.pptx
How Creative Agencies Leverage Project Management Software.pdf
PTS Company Brochure 2025 (1).pdf.......
Which alternative to Crystal Reports is best for small or large businesses.pdf
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
wealthsignaloriginal-com-DS-text-... (1).pdf
Transform Your Business with a Software ERP System
Understanding Forklifts - TECH EHS Solution
AI in Product Development-omnex systems
L1 - Introduction to python Backend.pptx
Softaken Excel to vCard Converter Software.pdf
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
ai tools demonstartion for schools and inter college
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Reimagine Home Health with the Power of Agentic AI​
Design an Analysis of Algorithms II-SECS-1021-03
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf

Improving Performance and Flexibility of Content Listings Using Criteria API

  • 1. Improving Performance and Flexibility of Content Listings Using Criteria API Nils Breunese
  • 2. Public Broadcaster since 1926 The Netherlands
  • 3. Online since 1994 Open-source CMS released in 1997
  • 4. Using Magnolia since 2010 Still migrating websites
  • 5. Tens of thousands of pages Multiple sites like that
  • 7. Thanks for the warning… Even 10 seconds would be way too long WARN info.magnolia.module.cache.filter.CacheFilter -- The following URL took longer than 10 seconds (63969 ms) to render. This might cause timeout exceptions on other requests to the same URI.
  • 8. Overview models Standard Templating Kit
  • 9. Tracking back from the template newsOverview.ftl (...) [#assign pager = model.pager]
 [#assign newsList = cmsfn.asContentMapList(pager.pageItems)!] (...)
  • 10. Constructing the pager AbstractItemListModel public STKPager getPager() throws RepositoryException {
 (...)
 return new STKPager(currentPageLink, getItems(), content);
 }
  • 11. Four step pipeline AbstractItemListModel public Collection<Node> getItems() throws RepositoryException {
 List<Node> itemsList = search();
 
 this.filter(itemsList);
 this.sort(itemsList);
 itemsList = this.shrink(itemsList);
 
 return itemsList;
 } 1 2 3 4
  • 12. Step 1a: Constructing the query TemplateCategoryUtil public static List<Node> getContentListByTemplateNames(...) { (...) StringBuffer sql = new StringBuffer( "select * from nt:base where jcr:path like '" + path + "/%'"); (...add 'mgnl:template=' clauses...) (...add 'ORDER BY' clauses...)
 return getWrappedNodesFromQuery(sql.toString(), repository, maxResultSize); } maxResultSize == Integer.MAX_VALUE
  • 13. Step 1b: Executing the query TemplateCategoryUtil public static List<Node> getContentListByTemplateNames(...) { (...)
 NodeIterator items = QueryUtil.search( repository, sql.toString(), Query.SQL, NodeTypes.Content.NAME); }
  • 14. Step 2: Filtering the item list STKDateContentUtil public static void filterDateContentList(...) {
 CollectionUtils.filter(itemsList, new Predicate() {
 @Override
 public boolean evaluate(Object object) {
 (...) return date.after(minDate) && date.before(maxDate);
 }
 });
 }
  • 15. Step 3: Time to sort STKDateContentUtil public static void sortDateContentList(...) {
 Collections.sort(itemsList, new Comparator<Node>() {
 @Override
 public int compare(Node c1, Node c2) {
 (...)
 if (StringUtils.equals(sortDirection, ASCENDING)) {
 return date2.compareTo(date1);
 }
 return date1.compareTo(date2);
 }
 });
 }
  • 16. Step 4: Shrinking the list STKTemplatingFunctions public List<Node> cutList(List<Node> itemsList, final int maxResults) {
 if (itemsList.size() > maxResults) {
 return itemsList.subList(0, maxResults);
 }
 return itemsList;
 } NewsOverviewModel passes Integer.MAX_VALUE, so shrink does effectively nothing in this case
  • 17. Step 5: Get the items from the pager STKPager public Collection getPageItems() {
 
 Collection subList = items;
 int offset = getOffset();
 if (count > 0) {
 int limit = maxResultsPerPage + offset;
 if (items.size() < limit) {
 limit = count;
 }
 subList = ((List) items).subList(offset, limit);
 
 }
 return subList;
 } maxResultsPerPage is typically something like 20
  • 18. When this becomes a problem We have multiple sites like this select * from nt:base where jcr:path like '/siteX/news/%' AND mgnl:template = 'standard-templating-kit:pages/stkNews' 20000 pages under website:/siteX/news Four step pipeline returns STKPager with 20000 items (page nodes) [#assign model.pager] [#assign newsList = cmsfn.asContentMapList(pager.pageItems)!] STKPager returns list with 20 page nodes 19980 Node objects created, but not rendered
  • 19. A query could do all steps at once JCR queries are pretty flexible
  • 20. Everything in a single JCR query Only 20 nodes returned SELECT * FROM nt:base WHERE jcr:path LIKE '/siteX/news/%' AND mgnl:template = 'standard-templating-kit:pages/stkNews' AND jcr:created < cast('2016-06-07T00:00:00.000Z' AS DATE) ORDER BY date ASCENDING LIMIT 20 OFFSET 20 Search Filter Sort Paging
  • 21. Criteria API For those familiar with Hibernate/JPA Criteria criteria = JCRCriteriaFactory.createCriteria()
 .setBasePath("/siteX/news")
 .add(Restrictions.eq( "@mgnl:template", "standard-templating-kit:pages/stkNews"))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
 .addOrder(Order.asc("date"))
 .setPaging(20, 1); 
 ResultIterator<...> items = criteria.execute(session).getItems(); Sort Paging Filter Search
  • 22. Criteria API for Magnolia CMS Magnolia module by Openmind
  • 24. Custom pager Only a single page worth of items public class VtkPager<T> extends STKPager { 
 private final List<? extends T> items; private final int pageSize;
 private final int count;
 
 (...)
 
 @Override
 public List<? extends T> getPageItems() {
 return items;
 } }
  • 25. Use it in your model classes VtkContentListModel (vpro) public abstract class VtkContentListModel ... {
 
 protected final VtkPager<ContentMap> pager;
 
 @Override
 public String execute() {
 pager = createPager();
 return super.execute();
 }
 
 protected abstract VtkPager<T> createPager(); (...) }
  • 26. Concrete Example VtkNewsOverviewModel (vpro) @Override
 protected VtkPager<Node> createPager() { (...)
 AdvancedResult result = JCRCriteriaFactory.createCriteria()
 .setBasePath(path)
 .add(Restrictions.in("@mgnl:template", templates))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate)) .addOrder(Order.asc("date")) .setPaging(itemsPerPage, pageNumberStartingFromOne) .execute(session);
 List<Node> items = new ArrayList<>();
 for (AdvancedResultItem item : result.getItems()) {
 items.add(item.getJCRNode());
 }
 
 int count = result.getTotalSize();
 
 return new VtkPager<>(link, items, content, itemsPerPage, count); }
  • 27. Still this. Was it all for nothing? :o( WARN info.magnolia.module.cache.filter.CacheFilter -- The following URL took longer than 10 seconds (63969 ms) to render. This might cause timeout exceptions on other requests to the same URI.
  • 28. Example VtkNewsOverviewModel (vpro) @Override
 protected VtkPager<Node> createPager() { (...)
 AdvancedResult result = JCRCriteriaFactory.createCriteria()
 .setBasePath(path)
 .add(Restrictions.in("@mgnl:template", templates))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate)) .addOrder(Order.asc("date")) .setPaging(itemsPerPage, pageNumberStartingFromOne) .execute(session);
 List<Node> items = new ArrayList<>();
 for (AdvancedResultItem item : result.getItems()) {
 items.add(item.getJCRNode());
 }
 
 int count = result.getTotalSize();
 
 return new VtkPager<>(link, items, content, itemsPerPage, count); } This call takes 10-60+ seconds!
  • 29. AdvancedResultImpl (jcr-criteria) @Override
 public int getTotalSize() {
 if (totalResults == null) {
 int queryTotalSize = -1;
 try { // jcrQueryResult instanceof JackrabbitQueryResult) {
 Method m = jcrQueryResult.getClass().getMethod("getTotalSize");
 queryTotalSize = (int) m.invoke(jcrQueryResult);
 } catch (InvocationTargetException | IllegalAccessException e) {
 LOG.error(e.getMessage(), e);
 } catch (NoSuchMethodException e) {
 
 }
 if (queryTotalSize == -1 && (itemsPerPage == 0 || applyLocalPaging)) {
 try {
 totalResults = (int) jcrQueryResult.getNodes().getSize();
 } catch (RepositoryException e) {
 // ignore, the standard total size will be returned
 }
 }
 
 if (queryTotalSize == -1) {
 totalResults = queryCounter.getAsInt();
 } else {
 totalResults = queryTotalSize;
 
 }
 }
 return totalResults;
 } We end up here
  • 30. jackrabbit-core 2.8.0 protected void getResults(long size) throws RepositoryException {
 (...)
 result = executeQuery(maxResultSize); // Lucene query (...) // Doesn’t use result.getSize(), call collectScoreNodes(...) } private void collectScoreNodes(...) {
 while (collector.size() < maxResults) {
 ScoreNode[] sn = hits.nextScoreNodes(); (...)
 // check access
 if (isAccessGranted(sn)) {
 collector.add(sn);
 } else {
 invalid++;
 }
 }
 } QueryResultImpl
  • 31. It used to be fast! https://issues.apache.org/jira/browse/JCR-3858
  • 32. jackrabbit-core 2.10.0+ protected void getResults(long size) throws RepositoryException { (...) if (sizeEstimate) {
 numResults = result.getSize(); // Use count from Lucene
 
 } else {
 // do things the Jackrabbit 2.8.0 way
 (...)
 } (...) } QueryResultImpl
  • 33. Enable Jackrabbit’s 'sizeEstimate' Jackrabbit 2.10+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex"> (...) <param name="sizeEstimate" value="true"/> </SearchIndex>
  • 34. Rendering times down to 1-2 seconds Bingo
  • 36. Feel free to contact me Nils Breunese @breun n.breunese@vpro.nl