diff --git a/http-tests/proxy/GET-proxied-external-502.sh b/http-tests/proxy/GET-proxied-external-502.sh
index 3e297c65b..c0c6bfc45 100755
--- a/http-tests/proxy/GET-proxied-external-502.sh
+++ b/http-tests/proxy/GET-proxied-external-502.sh
@@ -19,6 +19,7 @@ add-agent-to-group.sh \
curl -k -w "%{http_code}\n" -o /dev/null -s \
-G \
+ -H "Accept: application/n-triples" \
-E "$AGENT_CERT_FILE":"$AGENT_CERT_PWD" \
--data-urlencode "uri=http://f1d2d4cf-90bb-4f5b-ae4b-921e584b6edd.org" \
"$END_USER_BASE_URL" \
diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilter.java
index 23f635a00..964fefbb9 100644
--- a/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilter.java
+++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/request/ProxyRequestFilter.java
@@ -16,7 +16,7 @@
*/
package com.atomgraph.linkeddatahub.server.filter.request;
-import com.atomgraph.core.MediaTypes;
+import com.atomgraph.client.MediaTypes;
import com.atomgraph.client.util.HTMLMediaTypePredicate;
import com.atomgraph.client.vocabulary.AC;
import com.atomgraph.core.exception.BadGatewayException;
@@ -84,15 +84,14 @@
* ACL is not checked for proxy requests: the proxy is a global transport function, not a document
* operation. Access control is enforced by the target endpoint.
*
- * This filter intentionally does not proxy requests from clients that explicitly accept
- * (X)HTML. Rendering arbitrary external URIs as (X)HTML through the full server-side pipeline
- * (SPARQL DESCRIBE + XSLT) for every browser-originated proxy request would cause unbounded resource
- * exhaustion — a connection-pool and CPU amplification attack vector. Instead, requests whose
- * {@code Accept} header contains a non-wildcard {@code text/html} or {@code application/xhtml+xml}
- * type fall through to the downstream handler, which serves the LDH application shell; the
- * client-side Saxon-JS layer then issues a second, RDF-typed request that does hit this
- * filter and is handled cheaply. Pure API clients that send only {@code *}{@code /*} (e.g. curl)
- * reach the proxy because they do not list an explicit HTML type.
+ * This filter does not proxy requests from clients that explicitly accept (X)HTML.
+ * Rendering arbitrary external URIs as (X)HTML through the full server-side pipeline
+ * (SPARQL DESCRIBE + XSLT) is expensive and creates a resource-exhaustion attack vector.
+ * When the {@code Accept} header contains a non-wildcard {@code text/html} or
+ * {@code application/xhtml+xml} type, the filter returns immediately so the downstream handler
+ * serves the LDH application shell; the client-side Saxon-JS layer then issues a second, RDF-typed
+ * request that hits this filter and is proxied cheaply. Pure API clients that send only
+ * {@code *}{@code /*} (e.g. curl) reach the proxy because they do not list an explicit HTML type.
*
* @author Martynas Jusevičius {@literal }
*/
@@ -102,11 +101,11 @@ public class ProxyRequestFilter implements ContainerRequestFilter
{
private static final Logger log = LoggerFactory.getLogger(ProxyRequestFilter.class);
- private static final MediaTypes MEDIA_TYPES = new MediaTypes();
private static final Pattern LINK_SPLITTER = Pattern.compile(",(?=\\s*<)");
@Inject com.atomgraph.linkeddatahub.Application system;
@Inject jakarta.inject.Provider> ontology;
+ @Inject MediaTypes mediaTypes;
@Context Request request;
@Override
@@ -117,26 +116,34 @@ public void filter(ContainerRequestContext requestContext) throws IOException
URI targetURI = targetOpt.get();
- // do not proxy requests from clients that explicitly accept (X)HTML — they expect the app shell,
- // which the downstream handler serves. Browsers list text/html as a non-wildcard type; pure API
- // clients (curl etc.) send only */* and must reach the proxy.
- // Defending against resource exhaustion: proxying + full server-side XSLT rendering for arbitrary
- // external URIs on every browser request would amplify CPU and connection-pool load unboundedly.
+ // do not proxy requests from clients that explicitly accept (X)HTML — they expect the app
+ // shell, which the downstream handler serves. Browsers list text/html as a non-wildcard type;
+ // pure API clients (curl etc.) send only */* and must reach the proxy.
+ // (X)HTML is not offered for proxied documents — rendering external RDF as HTML server-side
+ // (SPARQL DESCRIBE + XSLT) is expensive and creates a resource-exhaustion attack vector
boolean clientAcceptsHtml = requestContext.getAcceptableMediaTypes().stream()
.anyMatch(mt -> !mt.isWildcardType() && !mt.isWildcardSubtype() &&
(mt.isCompatible(MediaType.TEXT_HTML_TYPE) ||
mt.isCompatible(MediaType.APPLICATION_XHTML_XML_TYPE)));
if (clientAcceptsHtml) return;
- // negotiate the response format from RDF/SPARQL writable types
+ // negotiate the response format from RDF/SPARQL writable types only
+ // (client.MediaTypes prepends HTML/XHTML; strip them so selectVariant cannot pick them)
List writableTypes = new ArrayList<>(getMediaTypes().getWritable(Model.class));
writableTypes.addAll(getMediaTypes().getWritable(ResultSet.class));
+ writableTypes.removeIf(mt -> mt.isCompatible(MediaType.TEXT_HTML_TYPE) ||
+ mt.isCompatible(MediaType.APPLICATION_XHTML_XML_TYPE));
List variants = com.atomgraph.core.model.impl.Response.getVariants(
writableTypes,
getSystem().getSupportedLanguages(),
new ArrayList<>());
- Variant selectedVariant = getRequest().selectVariant(variants);
- if (selectedVariant == null) return; // client accepts no RDF/SPARQL type
+
+ Variant variant = getRequest().selectVariant(variants);
+ if (variant == null)
+ {
+ if (log.isTraceEnabled()) log.trace("Requested Variant {} is not on the list of acceptable Response Variants: {}", variant, variants);
+ throw new NotAcceptableException();
+ }
// strip #fragment (servers do not receive fragment identifiers)
if (targetURI.getFragment() != null)
@@ -156,7 +163,7 @@ public void filter(ContainerRequestContext requestContext) throws IOException
{
if (log.isDebugEnabled()) log.debug("Serving mapped URI from DataManager cache: {}", targetURI);
Model model = getSystem().getDataManager().loadModel(targetURI.toString());
- requestContext.abortWith(getResponse(model, Response.Status.OK, selectedVariant));
+ requestContext.abortWith(getResponse(model, Response.Status.OK, variant));
return;
}
@@ -174,7 +181,7 @@ public void filter(ContainerRequestContext requestContext) throws IOException
if (!description.isEmpty())
{
if (log.isDebugEnabled()) log.debug("Serving URI from namespace ontology: {}", targetURI);
- requestContext.abortWith(getResponse(description, Response.Status.OK, selectedVariant));
+ requestContext.abortWith(getResponse(description, Response.Status.OK, variant));
return;
}
}
@@ -221,7 +228,7 @@ else if (agentContext instanceof IDTokenSecurityContext idTokenSecurityContext)
{
// provide the target URI as a base URI hint so ModelProvider / HtmlJsonLDReader can resolve relative references
clientResponse.getHeaders().putSingle(com.atomgraph.core.io.ModelProvider.REQUEST_URI_HEADER, targetURI.toString());
- requestContext.abortWith(getResponse(clientResponse, selectedVariant));
+ requestContext.abortWith(getResponse(clientResponse, variant));
}
}
catch (MessageBodyProviderNotFoundException ex)
@@ -381,14 +388,13 @@ public Optional getOntology()
}
/**
- * Returns the media types registry.
- * Core MediaTypes do not include (X)HTML types, which is what we want here.
+ * Returns the media types registry used for content negotiation and outbound {@code Accept} headers.
*
* @return media types
*/
public MediaTypes getMediaTypes()
{
- return MEDIA_TYPES;
+ return mediaTypes;
}
/**
diff --git a/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java b/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java
index 5c9bc4785..770a3dbd2 100644
--- a/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java
+++ b/src/main/java/com/atomgraph/linkeddatahub/server/filter/response/ResponseHeadersFilter.java
@@ -26,6 +26,7 @@
import com.atomgraph.linkeddatahub.server.model.impl.Dispatcher;
import com.atomgraph.linkeddatahub.server.security.AuthorizationContext;
import com.atomgraph.linkeddatahub.vocabulary.ACL;
+import com.atomgraph.linkeddatahub.vocabulary.LAPP;
import java.io.IOException;
import java.net.URI;
import java.util.Optional;
@@ -80,6 +81,8 @@ public void filter(ContainerRequestContext request, ContainerResponseContext res
if (!isProxyRequest && getApplication().isPresent())
{
Application application = getApplication().get();
+ // add Link rel=lapp:application
+ response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(application.getURI()), LAPP.application.getURI(), null));
// add Link rel=ldt:ontology, if the ontology URI is specified
if (application.getOntology() != null)
response.getHeaders().add(HttpHeaders.LINK, new Link(URI.create(application.getOntology().getURI()), LDT.ontology.getURI(), null));
diff --git a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LAPP.java b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LAPP.java
index 479bf44d3..7ef0a28f1 100644
--- a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LAPP.java
+++ b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LAPP.java
@@ -91,4 +91,7 @@ public static String getURI()
/** Origin property for subdomain-based application matching */
public static final ObjectProperty origin = m_model.createObjectProperty(NS + "origin");
+ /** Application property (for Link header rel) */
+ public static final ObjectProperty application = m_model.createObjectProperty( NS + "application" );
+
}
diff --git a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LDH.java b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LDH.java
index 17414f681..e8dcaebfe 100644
--- a/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LDH.java
+++ b/src/main/java/com/atomgraph/linkeddatahub/vocabulary/LDH.java
@@ -92,9 +92,6 @@ public static String getURI()
/** Violation value property */
public static final DatatypeProperty violationValue = m_model.createDatatypeProperty( NS + "violationValue" );
- /** Access to property */
- public static final ObjectProperty access_to = m_model.createObjectProperty(NS + "access-to"); // TO-DO: move to client-side?
-
/** Request URI property */
public static final ObjectProperty requestUri = m_model.createObjectProperty(NS + "requestUri");
diff --git a/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java b/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java
index 00818c9de..e51e8aae9 100644
--- a/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java
+++ b/src/main/java/com/atomgraph/linkeddatahub/writer/XSLTWriterBase.java
@@ -90,7 +90,6 @@ public abstract class XSLTWriterBase extends com.atomgraph.client.writer.XSLTWri
@Inject jakarta.inject.Provider> application;
@Inject jakarta.inject.Provider dataManager;
@Inject jakarta.inject.Provider xsltExecSupplier;
- @Inject jakarta.inject.Provider> modes;
@Inject jakarta.inject.Provider crc;
@Inject jakarta.inject.Provider> authorizationContext;
@@ -134,9 +133,6 @@ public Map getParameters(MultivaluedMap Map getParameters(MultivaluedMap getModes(Set namespaces)
- {
- return getModes().stream().map(Mode::get).collect(Collectors.toList());
- }
-
- /**
- * Returns a list of enabled layout modes.
- *
- * @return list of modes
- */
- public List getModes()
- {
- return modes.get();
- }
-
@Override
public Set getSupportedNamespaces()
{
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/css/bootstrap.css b/src/main/webapp/static/com/atomgraph/linkeddatahub/css/bootstrap.css
index c4e40f8f1..323c7b577 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/css/bootstrap.css
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/css/bootstrap.css
@@ -1,5 +1,15 @@
html { height: 100%; }
-body { height: calc(100% - 120px); padding-top: 120px; padding-bottom: 0; }
+/* only the main navbar is fixed-top now; tab bar + action bar are sticky inside #tab-body */
+body { height: calc(100% - 55px); padding-top: 55px; padding-bottom: 0; }
+#tab-bar { position: sticky; top: 55px; z-index: 1000; margin-bottom: 0; }
+/* Override Bootstrap's overflow:auto which would make action-bar sticky relative to #tab-content instead of the viewport */
+#tab-content { overflow: visible; }
+#tab-bar.navbar-inner { min-height: 36px; padding: 4px 0; background: #ccc; box-shadow: none; }
+#tab-bar-list.nav-tabs { margin-bottom: 0; border-bottom: none; }
+#tab-bar-list.nav-tabs > li > a { color: #007fff; padding: 8px 12px; text-shadow: none; border-color: #aaa #aaa transparent; }
+#tab-bar-list.nav-tabs > li.active > a, #tab-bar .nav-tabs > li.active > a:hover { color: #555555; background: rgb(223, 223, 223); border-color: #aaa #aaa transparent; }
+#tab-bar-list .tab-close { margin-left: 4px; font-size: 10px; color: #888; cursor: pointer; vertical-align: middle; }
+#tab-bar-list .tab-close:hover { color: #333; }
body.embed { padding-top: 0; }
ul.dropdown-menu { max-height: 26em; overflow-x: hidden; overflow-y: auto; }
ul.dropdown-menu ul { margin: 0; }
@@ -17,16 +27,17 @@ ul.dropdown-menu ul { margin: 0; }
.navbar-form .input-append { margin-top: 10px; }
.navbar-form .input-append select { margin-top: 0; height: 34px; }
.navbar-form .btn-search { background-image: url('../icons/ic_search_white_24px.svg'); background-position: center center; background-repeat: no-repeat; width: 34px; height: 34px; }
-.action-bar { background-color: #dfdfdf; }
+.action-bar { position: sticky; top: var(--action-bar-top, 55px); z-index: 999; background: #dfdfdf; padding: 0; box-shadow: none; }
.action-bar form { margin-bottom: 0; }
.action-bar .span7 .row-fluid > * { margin-top: 10px; }
+.action-bar .row-fluid > .span2, .action-bar .row-fluid > .span3 { margin-top: 10px; }
.action-bar .add-constructor, .dropdown-menu .add-constructor { background-color: inherit; display: block; text-align: left; width: 100%; }
.action-bar .add-constructor:hover { color: #ffffff; background-color: #007af5; }
.action-bar .breadcrumb { background-color: inherit; margin-bottom: 0; padding-left: 0; padding-top: 5px; }
.action-bar .breadcrumb .container-logo { background-image: url('../icons/folder.svg'); background-position: left center; background-repeat: no-repeat; padding-left: 28px; }
.action-bar .breadcrumb .item-logo { background-image: url('../icons/file.svg'); background-position: left center; background-repeat: no-repeat; padding-left: 28px; }
.action-bar .breadcrumb .btn-group { margin-top: -4px; }
-.action-bar #breadcrumb-nav > .label-info { padding: 8px 15px; margin-right: 8px; font-size: inherit; background-color: #9954bb; }
+.action-bar .breadcrumb-nav > .label-info { padding: 8px 15px; margin-right: 8px; font-size: inherit; background-color: #9954bb; }
.action-bar #doc-controls { text-align: right; padding-top: 5px; }
.action-bar #doc-controls .btn-edit { margin-top: -5px; margin-left: 10px; }
.action-bar p.alert { margin-bottom: 0; }
@@ -107,10 +118,10 @@ li button.btn-edit-constructors, li button.btn-add-data, li button.btn-add-ontol
.caret.caret-reversed { border-bottom: 4px solid #000000; border-top-width: 0; }
.faceted-nav input[type=checkbox]:checked + span { font-weight: bold; }
.parallax-nav a { cursor: pointer; }
-#content-body { min-height: calc(100% - 14em); }
-#content-body > [about].row-fluid { overflow-x: auto; margin-bottom: 20px; }
-#content-body > [about].row-fluid, .constructor-triple.row-fluid { border-bottom: 2px solid rgb(223, 223, 223); }
-#content-body > [about].row-fluid.drag-over { border-bottom: 4px dotted #0f82f5; }
+.content-body { min-height: calc(100% - 14em); margin-top: 14px; }
+.content-body > [about].row-fluid.block { overflow-x: auto; margin-bottom: 20px; }
+.content-body > [about].row-fluid.block, .constructor-triple.row-fluid { border-bottom: 2px solid rgb(223, 223, 223); }
+.content-body > [about].row-fluid.block.drag-over { border-bottom: 4px dotted #0f82f5; }
.row-fluid.block { max-height: 80em; }
.row-fluid.block .drag-handle { display: none; width: 30px; background-color: #149bdf; background-image: radial-gradient(circle at 3px 3px, #0480be 1px, transparent 1.5px); background-size: 6px 6px; border-radius: 2px; cursor: move; }
.list-mode.active { background-image: url('../icons/ic_navigate_before_black_24px.svg'); }
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/acl/layout.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/acl/layout.xsl
index 0c4a69c4f..08664947c 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/acl/layout.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/acl/layout.xsl
@@ -32,18 +32,6 @@ exclude-result-prefixes="#all">
-
-
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/signup.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/signup.xsl
index 196a41081..8af4a9f6c 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/signup.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/admin/signup.xsl
@@ -47,7 +47,7 @@ xmlns:bs2="http://graphity.org/xsl/bootstrap/2.3.2"
exclude-result-prefixes="#all">
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block.xsl
index 49a4833e4..ca2ecde5c 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block.xsl
@@ -181,53 +181,59 @@ exclude-result-prefixes="#all"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -325,7 +331,7 @@ exclude-result-prefixes="#all"
-
+
@@ -348,75 +354,100 @@ exclude-result-prefixes="#all"
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/chart.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/chart.xsl
index 0f17e1fdb..7c3c0bd54 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/chart.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/chart.xsl
@@ -584,7 +584,7 @@ exclude-result-prefixes="#all"
-
+
@@ -774,7 +774,7 @@ exclude-result-prefixes="#all"
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/query.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/query.xsl
index d1aef2a84..5ab2a3ae1 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/query.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/query.xsl
@@ -189,7 +189,7 @@ exclude-result-prefixes="#all"
-
+
@@ -267,7 +267,7 @@ exclude-result-prefixes="#all"
-
+
@@ -380,7 +380,7 @@ exclude-result-prefixes="#all"
-
+
@@ -449,7 +449,7 @@ exclude-result-prefixes="#all"
-
+
@@ -495,7 +495,7 @@ exclude-result-prefixes="#all"
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/view.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/view.xsl
index 4d99429e4..0d1998b51 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/view.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/block/view.xsl
@@ -1741,7 +1741,7 @@ exclude-result-prefixes="#all"
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/form.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/form.xsl
index ef590b72d..8ed6f80d9 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/form.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/form.xsl
@@ -233,36 +233,11 @@ WHERE
-
-
-
+
@@ -907,7 +882,6 @@ WHERE
-
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/functions.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/functions.xsl
index d121bd30e..1453f2a70 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/functions.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/functions.xsl
@@ -41,8 +41,8 @@ exclude-result-prefixes="#all"
-
-
+
+
@@ -54,7 +54,7 @@ exclude-result-prefixes="#all"
-
+
@@ -67,7 +67,7 @@ exclude-result-prefixes="#all"
-
+
@@ -79,33 +79,20 @@ exclude-result-prefixes="#all"
)"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/merge-rdfxml.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/merge-rdfxml.xsl
index b9219fecd..9e0e05698 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/merge-rdfxml.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/merge-rdfxml.xsl
@@ -21,7 +21,7 @@
-
+
diff --git a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/modal.xsl b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/modal.xsl
index 091c3a4af..c268690ba 100644
--- a/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/modal.xsl
+++ b/src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/bootstrap/2.3.2/client/modal.xsl
@@ -154,14 +154,14 @@ LIMIT 10