https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/Head
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://www.nanopub.org/nschema#hasAssertion
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/assertion
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://www.nanopub.org/nschema#hasProvenance
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/provenance
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://www.nanopub.org/nschema#hasPublicationInfo
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/pubinfo
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
http://www.nanopub.org/nschema#Nanopublication
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/assertion
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
http://purl.org/dc/terms/description
Renders the schedule of an event as one SVG per day, with the rooms as lanes down the figure and the clock running left to right. It is the counterpart to the grid view, for a day of many rooms with few items in each — a workshop and tutorial day, where thirteen columns leave the grid's boxes too narrow to read. The width the grid has to divide between its columns goes to the time axis here, and every item gets a whole lane for its text: the axis is fitted to a plot area 1140 units wide, so a day fills the panel whatever it spans, and a very short day stops at 6 units a minute rather than stretching an hour across the figure. A day whose rooms hold many parallel items is the other way round better served by the grid, which gives each slot the height of its own duration to divide. Covers both the presentations that are part of the event and its workshop, tutorial and session sub-spaces, which are coloured differently and link to their own space pages. Each box states its own times, since a clock along the edges of an axis fitted to the day can be read to a few minutes at best, and then as many authors as the line has room for. Box text adapts to the box: the times, the authors and up to three title lines while the lane is whole, one centred title line once parallel items in the same room and slot have divided the lane between them, at font-size 9 below 20 units, and the whole title and author list in a hover tooltip throughout. Line length follows the box width, derived from the widest character of the real font; a line only breaks where the text runs past it, and a line that had to break inside a word resumes at the next character. The per-slot ranking joins two separately computed sub-selects rather than filtering a cross product, which the engine evaluated as a nested loop, and the room's lane index and the day's room count come from one such pass as well. Reads both the http:// and https:// schema.org namespaces. Where several valid nanopublications introduce the same talk or sub-space (e.g. an override published by another admin, which carries no supersedes link), only the most recently created one is used, so an item is never counted twice. Each box links with an explicit &context= naming the event, so that a talk opened from the schedule lands with the conference as its navigation context; without it Nanodash appends the context of the page the schedule happens to be rendered on, and from the schedule's own resource page that is the schedule, on which the part page renders none of its views.
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
http://purl.org/dc/terms/license
http://www.apache.org/licenses/LICENSE-2.0
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
https://w3id.org/kpxl/grlc/grlc-query
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
http://www.w3.org/2000/01/rdf-schema#label
Get the schedule of an event as SVG room lanes
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
https://w3id.org/kpxl/grlc/endpoint
https://w3id.org/np/l/nanopub-query-1.1/repo/full
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
https://w3id.org/kpxl/grlc/sparql
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix dct: <http://purl.org/dc/terms/>
prefix np: <http://www.nanopub.org/nschema#>
prefix npa: <http://purl.org/nanopub/admin/>
prefix npx: <http://purl.org/nanopub/x/>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix wd: <http://www.wikidata.org/entity/>
prefix schema: <https://schema.org/>
prefix schemaold: <http://schema.org/>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix pav: <http://purl.org/pav/>
prefix gen: <https://w3id.org/kpxl/gen/terms/>
prefix conf: <https://w3id.org/scholarlydata/ontology/conference-ontology.owl#>
select ?title (concat(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ', str(?w), ' ', str(?h),
'" width="', str(round(?w * 3 / 2)), '" height="', str(round(?h * 3 / 2)), '" font-family="sans-serif">',
?frags, '</svg>') as ?svg)
where {
{
select ?day (group_concat(?frag; separator="") as ?frags)
(max(?ybot) as ?maxy) (max(?xright) as ?maxx)
where {
# ============ talk boxes ============
{
select ?day ?frag (?by + ?bh as ?ybot) (?bx + ?bw as ?xright)
where {
{
select ?pres ?day ?room ?smin ?emin ?tlabel ?path ?ctxq ?fill ?stroke
(group_concat(distinct ?aname; separator=", ") as ?authors)
where {
graph npa:graph {
?np npa:hasValidSignatureForPublicKeyHash ?pk ;
np:hasAssertion ?a ; npx:introduces ?pres ; dct:created ?cr .
filter not exists { ?inv npx:invalidates ?np ; npa:hasValidSignatureForPublicKeyHash ?pk . }
filter not exists { ?np npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nw npx:introduces ?pres ; npa:hasValidSignatureForPublicKeyHash ?pkw ; dct:created ?crw .
filter(?crw > ?cr)
filter not exists { ?invw npx:invalidates ?nw ; npa:hasValidSignatureForPublicKeyHash ?pkw . }
filter not exists { ?nw npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sg { ?newer npx:supersedes ?np . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?ev)
} union {
values ?_resource_multi_iri {}
graph ?mg { ?_resource_multi_iri gen:isMaintainedBy ?ev }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kind ?rel ?path ?fill ?stroke) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?a { ?pres a ?kind ; ?rel ?ev . }
bind(concat("&context=", encode_for_uri(str(?ev))) as ?ctxq)
optional { graph ?a { ?pres schema:startDate ?sdA } }
optional { graph ?a { ?pres schemaold:startDate ?sdB } }
optional { graph ?a { ?pres schema:endDate ?edA } }
optional { graph ?a { ?pres schemaold:endDate ?edB } }
optional { graph ?a { ?pres schema:location ?loA } }
optional { graph ?a { ?pres schemaold:location ?loB } }
optional { graph ?a { ?pres rdfs:label ?lb } }
bind(coalesce(?sdA, ?sdB) as ?sd)
filter(bound(?sd))
bind(coalesce(?edA, ?edB) as ?ed)
bind(coalesce(str(?loA), str(?loB), "") as ?room)
bind(substr(str(?sd), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sd), 12, 2)) * 60 + xsd:integer(substr(str(?sd), 15, 2)) as ?smin)
bind(coalesce(xsd:integer(substr(str(?ed), 12, 2)) * 60 + xsd:integer(substr(str(?ed), 15, 2)), ?smin + 30) as ?emin)
bind(coalesce(str(?lb), "(untitled)") as ?tlabel)
optional {
graph ?a { ?pres pav:authoredBy ?ag }
optional { graph ?pi2 { ?ag foaf:name ?agn } }
bind(coalesce(?agn, replace(str(?ag), "^.*/", "")) as ?aname)
}
} group by ?pres ?day ?room ?smin ?emin ?tlabel ?path ?ctxq ?fill ?stroke
}
# Rank within the (day, room, slot) cell and how many share it, in ONE
# self-join: with the sub-space branch added, a second pass over the base
# pattern ran the query service out of budget (HTTP 503).
{
select ?pres (sum(if(?keyO <= ?keyR, 1, 0)) as ?rank)
(count(distinct ?o) as ?nslot)
where {
# Each side is its own sub-select, joined on (day, room, start). Written as one
# group with a filter, the engine re-evaluated the whole O side once per R row,
# which took about 9s on its own; this way each side is computed once.
{ select ?pres ?dayR ?roomR ?sminR ?keyR where {
graph npa:graph {
?npR npa:hasValidSignatureForPublicKeyHash ?pkR ;
np:hasAssertion ?a2 ; npx:introduces ?pres ; dct:created ?crR .
filter not exists { ?invR npx:invalidates ?npR ; npa:hasValidSignatureForPublicKeyHash ?pkR . }
filter not exists { ?npR npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwR npx:introduces ?pres ; npa:hasValidSignatureForPublicKeyHash ?pkwR ; dct:created ?crwR .
filter(?crwR > ?crR)
filter not exists { ?invwR npx:invalidates ?nwR ; npa:hasValidSignatureForPublicKeyHash ?pkwR . }
filter not exists { ?nwR npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgR { ?newerR npx:supersedes ?npR . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evR)
} union {
values ?_resource_multi_iri {}
graph ?mgR { ?_resource_multi_iri gen:isMaintainedBy ?evR }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kind2 ?rel2 ?pathR ?fillR ?strokeR) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?a2 { ?pres a ?kind2 ; ?rel2 ?evR . }
optional { graph ?a2 { ?pres schema:startDate ?sdAR } }
optional { graph ?a2 { ?pres schemaold:startDate ?sdBR } }
optional { graph ?a2 { ?pres schema:endDate ?edAR } }
optional { graph ?a2 { ?pres schemaold:endDate ?edBR } }
optional { graph ?a2 { ?pres schema:location ?loAR } }
optional { graph ?a2 { ?pres schemaold:location ?loBR } }
optional { graph ?a2 { ?pres rdfs:label ?lbR } }
optional { graph ?a2 { ?pres schema:position ?psR } }
bind(coalesce(?sdAR, ?sdBR) as ?sdR)
filter(bound(?sdR))
bind(coalesce(?edAR, ?edBR) as ?edR)
bind(coalesce(str(?loAR), str(?loBR), "") as ?roomR)
bind(substr(str(?sdR), 1, 10) as ?dayR)
bind(xsd:integer(substr(str(?sdR), 12, 2)) * 60 + xsd:integer(substr(str(?sdR), 15, 2)) as ?sminR)
bind(coalesce(xsd:integer(substr(str(?edR), 12, 2)) * 60 + xsd:integer(substr(str(?edR), 15, 2)), ?sminR + 30) as ?eminR)
bind(coalesce(str(?lbR), "(untitled)") as ?tlabelR)
bind(concat(str(1000 + coalesce(?psR, 999)), ?tlabelR) as ?keyR)
} }
{ select ?o ?dayR ?roomR ?sminR ?keyO where { graph npa:graph {
?npO npa:hasValidSignatureForPublicKeyHash ?pkO ;
np:hasAssertion ?ao ; npx:introduces ?o ; dct:created ?crO .
filter not exists { ?invO npx:invalidates ?npO ; npa:hasValidSignatureForPublicKeyHash ?pkO . }
filter not exists { ?npO npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwO npx:introduces ?o ; npa:hasValidSignatureForPublicKeyHash ?pkwO ; dct:created ?crwO .
filter(?crwO > ?crO)
filter not exists { ?invwO npx:invalidates ?nwO ; npa:hasValidSignatureForPublicKeyHash ?pkwO . }
filter not exists { ?nwO npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgO { ?newerO npx:supersedes ?npO . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evO)
} union {
values ?_resource_multi_iri {}
graph ?mgO { ?_resource_multi_iri gen:isMaintainedBy ?evO }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindo ?relo ?pathO ?fillO ?strokeO) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ao { ?o a ?kindo ; ?relo ?evO . }
optional { graph ?ao { ?o schema:startDate ?sdAO } }
optional { graph ?ao { ?o schemaold:startDate ?sdBO } }
optional { graph ?ao { ?o schema:endDate ?edAO } }
optional { graph ?ao { ?o schemaold:endDate ?edBO } }
optional { graph ?ao { ?o schema:location ?loAO } }
optional { graph ?ao { ?o schemaold:location ?loBO } }
optional { graph ?ao { ?o rdfs:label ?lbO } }
optional { graph ?ao { ?o schema:position ?psO } }
bind(coalesce(?sdAO, ?sdBO) as ?sdO)
filter(bound(?sdO))
bind(coalesce(?edAO, ?edBO) as ?edO)
bind(coalesce(str(?loAO), str(?loBO), "") as ?roomR)
bind(substr(str(?sdO), 1, 10) as ?dayR)
bind(xsd:integer(substr(str(?sdO), 12, 2)) * 60 + xsd:integer(substr(str(?sdO), 15, 2)) as ?sminR)
bind(coalesce(xsd:integer(substr(str(?edO), 12, 2)) * 60 + xsd:integer(substr(str(?edO), 15, 2)), ?sminR + 30) as ?eminO)
bind(coalesce(str(?lbO), "(untitled)") as ?tlabelO)
bind(concat(str(1000 + coalesce(?psO, 999)), ?tlabelO) as ?keyO)
} }
} group by ?pres
}
# column index of the room
{
# the room's column index and the day's room count from one pass: the
# conditional count is the old self-join, with the filter lifted so that the
# same group also yields the total (as the rank/slot-count select does above)
select ?day ?room (count(distinct if(str(?r2) <= str(?room), ?r2, ?room)) - 1 as ?col)
(count(distinct ?r2) as ?ncol) where {
{ select distinct ?day ?room where {
graph npa:graph {
?npC npa:hasValidSignatureForPublicKeyHash ?pkC ;
np:hasAssertion ?ac1 ; npx:introduces ?c1 ; dct:created ?crC .
filter not exists { ?invC npx:invalidates ?npC ; npa:hasValidSignatureForPublicKeyHash ?pkC . }
filter not exists { ?npC npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwC npx:introduces ?c1 ; npa:hasValidSignatureForPublicKeyHash ?pkwC ; dct:created ?crwC .
filter(?crwC > ?crC)
filter not exists { ?invwC npx:invalidates ?nwC ; npa:hasValidSignatureForPublicKeyHash ?pkwC . }
filter not exists { ?nwC npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgC { ?newerC npx:supersedes ?npC . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evC)
} union {
values ?_resource_multi_iri {}
graph ?mgC { ?_resource_multi_iri gen:isMaintainedBy ?evC }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindc1 ?relc1 ?pathC ?fillC ?strokeC) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ac1 { ?c1 a ?kindc1 ; ?relc1 ?evC . }
optional { graph ?ac1 { ?c1 schema:startDate ?sdAC } }
optional { graph ?ac1 { ?c1 schemaold:startDate ?sdBC } }
optional { graph ?ac1 { ?c1 schema:endDate ?edAC } }
optional { graph ?ac1 { ?c1 schemaold:endDate ?edBC } }
optional { graph ?ac1 { ?c1 schema:location ?loAC } }
optional { graph ?ac1 { ?c1 schemaold:location ?loBC } }
optional { graph ?ac1 { ?c1 rdfs:label ?lbC } }
bind(coalesce(?sdAC, ?sdBC) as ?sdC)
filter(bound(?sdC))
bind(coalesce(?edAC, ?edBC) as ?edC)
bind(coalesce(str(?loAC), str(?loBC), "") as ?room)
bind(substr(str(?sdC), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sdC), 12, 2)) * 60 + xsd:integer(substr(str(?sdC), 15, 2)) as ?sminC)
bind(coalesce(xsd:integer(substr(str(?edC), 12, 2)) * 60 + xsd:integer(substr(str(?edC), 15, 2)), ?sminC + 30) as ?eminC)
bind(coalesce(str(?lbC), "(untitled)") as ?tlabelC) } }
{ select distinct ?dayD ?r2 where {
graph npa:graph {
?npD npa:hasValidSignatureForPublicKeyHash ?pkD ;
np:hasAssertion ?ac2 ; npx:introduces ?c2 ; dct:created ?crD .
filter not exists { ?invD npx:invalidates ?npD ; npa:hasValidSignatureForPublicKeyHash ?pkD . }
filter not exists { ?npD npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwD npx:introduces ?c2 ; npa:hasValidSignatureForPublicKeyHash ?pkwD ; dct:created ?crwD .
filter(?crwD > ?crD)
filter not exists { ?invwD npx:invalidates ?nwD ; npa:hasValidSignatureForPublicKeyHash ?pkwD . }
filter not exists { ?nwD npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgD { ?newerD npx:supersedes ?npD . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evD)
} union {
values ?_resource_multi_iri {}
graph ?mgD { ?_resource_multi_iri gen:isMaintainedBy ?evD }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindc2 ?relc2 ?pathD ?fillD ?strokeD) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ac2 { ?c2 a ?kindc2 ; ?relc2 ?evD . }
optional { graph ?ac2 { ?c2 schema:startDate ?sdAD } }
optional { graph ?ac2 { ?c2 schemaold:startDate ?sdBD } }
optional { graph ?ac2 { ?c2 schema:endDate ?edAD } }
optional { graph ?ac2 { ?c2 schemaold:endDate ?edBD } }
optional { graph ?ac2 { ?c2 schema:location ?loAD } }
optional { graph ?ac2 { ?c2 schemaold:location ?loBD } }
optional { graph ?ac2 { ?c2 rdfs:label ?lbD } }
bind(coalesce(?sdAD, ?sdBD) as ?sdD)
filter(bound(?sdD))
bind(coalesce(?edAD, ?edBD) as ?edD)
bind(coalesce(str(?loAD), str(?loBD), "") as ?r2)
bind(substr(str(?sdD), 1, 10) as ?dayD)
bind(xsd:integer(substr(str(?sdD), 12, 2)) * 60 + xsd:integer(substr(str(?sdD), 15, 2)) as ?sminD)
bind(coalesce(xsd:integer(substr(str(?edD), 12, 2)) * 60 + xsd:integer(substr(str(?edD), 15, 2)), ?sminD + 30) as ?eminD)
bind(coalesce(str(?lbD), "(untitled)") as ?tlabelD) } }
filter(?dayD = ?day)
} group by ?day ?room
}
{
select ?day (min(?sminY) as ?dstart) (max(?eminY) as ?dend) where {
graph npa:graph {
?npY npa:hasValidSignatureForPublicKeyHash ?pkY ;
np:hasAssertion ?ay1 ; npx:introduces ?y1 ; dct:created ?crY .
filter not exists { ?invY npx:invalidates ?npY ; npa:hasValidSignatureForPublicKeyHash ?pkY . }
filter not exists { ?npY npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwY npx:introduces ?y1 ; npa:hasValidSignatureForPublicKeyHash ?pkwY ; dct:created ?crwY .
filter(?crwY > ?crY)
filter not exists { ?invwY npx:invalidates ?nwY ; npa:hasValidSignatureForPublicKeyHash ?pkwY . }
filter not exists { ?nwY npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgY { ?newerY npx:supersedes ?npY . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evY)
} union {
values ?_resource_multi_iri {}
graph ?mgY { ?_resource_multi_iri gen:isMaintainedBy ?evY }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindy1 ?rely1 ?pathY ?fillY ?strokeY) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ay1 { ?y1 a ?kindy1 ; ?rely1 ?evY . }
optional { graph ?ay1 { ?y1 schema:startDate ?sdAY } }
optional { graph ?ay1 { ?y1 schemaold:startDate ?sdBY } }
optional { graph ?ay1 { ?y1 schema:endDate ?edAY } }
optional { graph ?ay1 { ?y1 schemaold:endDate ?edBY } }
optional { graph ?ay1 { ?y1 schema:location ?loAY } }
optional { graph ?ay1 { ?y1 schemaold:location ?loBY } }
optional { graph ?ay1 { ?y1 rdfs:label ?lbY } }
bind(coalesce(?sdAY, ?sdBY) as ?sdY)
filter(bound(?sdY))
bind(coalesce(?edAY, ?edBY) as ?edY)
bind(coalesce(str(?loAY), str(?loBY), "") as ?roomY)
bind(substr(str(?sdY), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sdY), 12, 2)) * 60 + xsd:integer(substr(str(?sdY), 15, 2)) as ?sminY)
bind(coalesce(xsd:integer(substr(str(?edY), 12, 2)) * 60 + xsd:integer(substr(str(?edY), 15, 2)), ?sminY + 30) as ?eminY)
bind(coalesce(str(?lbY), "(untitled)") as ?tlabelY)
} group by ?day
}
# Rooms run down the figure as lanes and the clock runs left to right. A day
# of many rooms with few items in each — a workshop and tutorial day — reads
# far better this way round: the width the vertical grid has to divide between
# thirteen columns goes to the time axis instead, and every item gets a whole
# lane for its text. The axis is fitted to a plot area 1140 units wide, so a
# day fills the panel whatever it spans, and a very short one stops at 6 units
# a minute rather than stretching an hour across the whole figure.
bind(if(?dend > ?dstart, ?dend - ?dstart, 1) as ?dspan)
bind(if(1140 / ?dspan < 6.0, floor(114000 / ?dspan) / 100, 6.0) as ?ppm)
bind(112 + xsd:integer(floor((?smin - ?dstart) * ?ppm)) as ?bx)
# 3 units of the box go to the gap that separates it from the next one, but
# never the whole box: an item recorded as lasting no time still gets a sliver
bind(if(xsd:integer(floor((?emin - ?smin) * ?ppm)) < 9, 6,
xsd:integer(floor((?emin - ?smin) * ?ppm)) - 3) as ?bw)
# Parallel items in one room and slot divide their lane the way they divide a
# slot in the vertical grid, and their text drops out as the share gets thin.
bind(30 + ?col * 66 as ?ly)
bind(xsd:integer(floor(60 / ?nslot)) as ?lh)
bind(?ly + (?rank - 1) * ?lh as ?by)
bind(if(?lh < 4, 1, ?lh - 3) as ?bh)
# Text budgets follow the box width. 6.21px is the widest character at font-size
# 10, measured against the real font: on a nine-hour day a box of 230 minutes
# holds 75 characters a line and a full-day one 180. Three lines is all a 57-unit
# lane holds, and a box too narrow for its title keeps the whole of it in its
# tooltip. A line that had to break inside a word resumes at the next character,
# not past a space that is not there.
bind(if(floor((?bw - 14) / 6.21) < 6, 6, xsd:integer(floor((?bw - 14) / 6.21))) as ?cap)
bind(concat("^(.{0,", str(?cap), "})\\s.*$") as ?wrapx)
# a line only breaks where the text runs past the cap: greedy matching would
# otherwise break a title that fits whole at its last space
bind(replace(?tlabel, ?wrapx, "$1") as ?ln1raw)
bind(if(strlen(?tlabel) <= ?cap, ?tlabel,
if(strlen(?ln1raw) > ?cap, substr(?ln1raw, 1, ?cap), ?ln1raw)) as ?ln1)
bind(if(strlen(?tlabel) > strlen(?ln1),
substr(?tlabel, strlen(?ln1) + if(substr(?tlabel, strlen(?ln1) + 1, 1) = " ", 2, 1)), "") as ?rest1)
bind(replace(?rest1, ?wrapx, "$1") as ?ln2raw)
bind(if(strlen(?rest1) <= ?cap, ?rest1,
if(strlen(?ln2raw) > ?cap, substr(?ln2raw, 1, ?cap), ?ln2raw)) as ?ln2)
bind(if(strlen(?rest1) > strlen(?ln2),
substr(?rest1, strlen(?ln2) + if(substr(?rest1, strlen(?ln2) + 1, 1) = " ", 2, 1)), "") as ?rest2)
bind(replace(?rest2, ?wrapx, "$1") as ?ln3raw)
bind(if(strlen(?rest2) <= ?cap, ?rest2,
if(strlen(?ln3raw) > ?cap, substr(?ln3raw, 1, ?cap), ?ln3raw)) as ?ln3)
bind(if(strlen(?rest2) > strlen(?ln3),
substr(?rest2, strlen(?ln3) + if(substr(?rest2, strlen(?ln3) + 1, 1) = " ", 2, 1)), "") as ?rest3)
# the same lines in the form that ends the text: an ellipsis where more remains,
# replacing the last character rather than being appended past the cap
bind(if(strlen(?rest2) > 0, concat(substr(?ln2, 1, ?cap - 1), "…"), ?ln2) as ?el2)
bind(if(strlen(?rest3) > 0, concat(substr(?ln3, 1, ?cap - 1), "…"), ?ln3) as ?el3)
bind(if(floor((?bw - 2) / 6.21) < 6, 6, xsd:integer(floor((?bw - 2) / 6.21))) as ?capl)
bind(if(strlen(?tlabel) > ?capl, concat(substr(?tlabel, 1, ?capl - 1), "…"), ?tlabel) as ?l1c)
# Every box states its own times. A clock along the edges of an axis fitted to
# the day can be read to a few minutes at best, and a 14:10 start is a thing a
# reader wants exactly; the authors follow, as many as the line has room for.
bind(xsd:integer(floor(?smin / 60)) as ?sh)
bind(xsd:integer(floor(?emin / 60)) as ?eh)
bind(concat(
if(?sh < 10, "0", ""), str(?sh), ":", if(?smin - ?sh * 60 < 10, "0", ""), str(?smin - ?sh * 60),
"–",
if(?eh < 10, "0", ""), str(?eh), ":", if(?emin - ?eh * 60 < 10, "0", ""), str(?emin - ?eh * 60)) as ?times)
bind(if(?cap - 14 < 4, 4, ?cap - 14) as ?acap)
bind(if(strlen(?authors) > ?acap,
concat(replace(substr(?authors, 1, ?acap - 2), ",[^,]*$", ""), " …"),
?authors) as ?authShort)
bind(if(strlen(?authShort) > 0, concat(?times, " · ", ?authShort), ?times) as ?meta)
bind(concat(
'<a href="', ?path, encode_for_uri(str(?pres)), ?ctxq, '">',
'<rect x="', str(?bx), '" y="', str(?by), '" width="', str(?bw), '" height="', str(?bh),
'" rx="3" fill="', ?fill, '" stroke="', ?stroke, '"></rect>',
# Whatever is left of the text, the whole of it stays in the tooltip.
'<title>', replace(replace(replace(?tlabel, "&", "&"), "<", "<"), ">", ">"), if(strlen(?authors) > 0, concat(' — ', replace(replace(replace(?authors, "&", "&"), "<", "<"), ">", ">")), ''), '</title>',
# The text itself adapts to the box: the times, the authors and up to three
# title lines while the lane is whole (57 units), one centred title line
# once parallel items have divided it, at font-size 9 below 20 units, and
# nothing but the tooltip below 11.
if(?bh >= 44, concat(
'<text x="', str(?bx + 8), '" y="', str(?by + 15), '" font-size="9" font-weight="bold" fill="#33475b">',
replace(replace(replace(?meta, "&", "&"), "<", "<"), ">", ">"), '</text>',
'<text x="', str(?bx + 8), '" y="', str(?by + 29), '" font-size="10" fill="#12263a">',
'<tspan x="', str(?bx + 8), '" y="', str(?by + 29), '">', replace(replace(replace(?ln1, "&", "&"), "<", "<"), ">", ">"), '</tspan>',
if(strlen(?ln2) > 0, concat('<tspan x="', str(?bx + 8), '" y="', str(?by + 41), '">', replace(replace(replace(if(?bh >= 56, ?ln2, ?el2), "&", "&"), "<", "<"), ">", ">"), '</tspan>'), ''),
if(?bh >= 56 && strlen(?ln3) > 0, concat('<tspan x="', str(?bx + 8), '" y="', str(?by + 53), '">', replace(replace(replace(?el3, "&", "&"), "<", "<"), ">", ">"), '</tspan>'), ''),
'</text>'),
if(?bh >= 11,
concat('<text x="', str(?bx + 8), '" y="', str(?by + ?bh / 2 + if(?bh >= 20, 3.5, 3)),
'" font-size="', if(?bh >= 20, "10", "9"), '" fill="#12263a">',
replace(replace(replace(?l1c, "&", "&"), "<", "<"), ">", ">"), '</text>'), '')),
'</a>') as ?frag)
}
}
union
# ============ room lanes down the left ============
{
select ?day ?frag (?ly + 60 as ?ybot) (104 as ?xright)
where {
{
select distinct ?day ?room where {
graph npa:graph {
?npH npa:hasValidSignatureForPublicKeyHash ?pkH ;
np:hasAssertion ?ah1 ; npx:introduces ?h1 ; dct:created ?crH .
filter not exists { ?invH npx:invalidates ?npH ; npa:hasValidSignatureForPublicKeyHash ?pkH . }
filter not exists { ?npH npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwH npx:introduces ?h1 ; npa:hasValidSignatureForPublicKeyHash ?pkwH ; dct:created ?crwH .
filter(?crwH > ?crH)
filter not exists { ?invwH npx:invalidates ?nwH ; npa:hasValidSignatureForPublicKeyHash ?pkwH . }
filter not exists { ?nwH npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgH { ?newerH npx:supersedes ?npH . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evH)
} union {
values ?_resource_multi_iri {}
graph ?mgH { ?_resource_multi_iri gen:isMaintainedBy ?evH }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindh1 ?relh1 ?pathH ?fillH ?strokeH) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ah1 { ?h1 a ?kindh1 ; ?relh1 ?evH . }
optional { graph ?ah1 { ?h1 schema:startDate ?sdAH } }
optional { graph ?ah1 { ?h1 schemaold:startDate ?sdBH } }
optional { graph ?ah1 { ?h1 schema:endDate ?edAH } }
optional { graph ?ah1 { ?h1 schemaold:endDate ?edBH } }
optional { graph ?ah1 { ?h1 schema:location ?loAH } }
optional { graph ?ah1 { ?h1 schemaold:location ?loBH } }
optional { graph ?ah1 { ?h1 rdfs:label ?lbH } }
bind(coalesce(?sdAH, ?sdBH) as ?sdH)
filter(bound(?sdH))
bind(coalesce(?edAH, ?edBH) as ?edH)
bind(coalesce(str(?loAH), str(?loBH), "") as ?room)
bind(substr(str(?sdH), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sdH), 12, 2)) * 60 + xsd:integer(substr(str(?sdH), 15, 2)) as ?sminH)
bind(coalesce(xsd:integer(substr(str(?edH), 12, 2)) * 60 + xsd:integer(substr(str(?edH), 15, 2)), ?sminH + 30) as ?eminH)
bind(coalesce(str(?lbH), "(untitled)") as ?tlabelH) }
}
{
select ?day ?room (count(distinct if(str(?r3) <= str(?room), ?r3, ?room)) - 1 as ?hcol)
(count(distinct ?r3) as ?nhcol) where {
{ select distinct ?day ?room where {
graph npa:graph {
?npE npa:hasValidSignatureForPublicKeyHash ?pkE ;
np:hasAssertion ?ae1 ; npx:introduces ?e1 ; dct:created ?crE .
filter not exists { ?invE npx:invalidates ?npE ; npa:hasValidSignatureForPublicKeyHash ?pkE . }
filter not exists { ?npE npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwE npx:introduces ?e1 ; npa:hasValidSignatureForPublicKeyHash ?pkwE ; dct:created ?crwE .
filter(?crwE > ?crE)
filter not exists { ?invwE npx:invalidates ?nwE ; npa:hasValidSignatureForPublicKeyHash ?pkwE . }
filter not exists { ?nwE npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgE { ?newerE npx:supersedes ?npE . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evE)
} union {
values ?_resource_multi_iri {}
graph ?mgE { ?_resource_multi_iri gen:isMaintainedBy ?evE }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kinde1 ?rele1 ?pathE ?fillE ?strokeE) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ae1 { ?e1 a ?kinde1 ; ?rele1 ?evE . }
optional { graph ?ae1 { ?e1 schema:startDate ?sdAE } }
optional { graph ?ae1 { ?e1 schemaold:startDate ?sdBE } }
optional { graph ?ae1 { ?e1 schema:endDate ?edAE } }
optional { graph ?ae1 { ?e1 schemaold:endDate ?edBE } }
optional { graph ?ae1 { ?e1 schema:location ?loAE } }
optional { graph ?ae1 { ?e1 schemaold:location ?loBE } }
optional { graph ?ae1 { ?e1 rdfs:label ?lbE } }
bind(coalesce(?sdAE, ?sdBE) as ?sdE)
filter(bound(?sdE))
bind(coalesce(?edAE, ?edBE) as ?edE)
bind(coalesce(str(?loAE), str(?loBE), "") as ?room)
bind(substr(str(?sdE), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sdE), 12, 2)) * 60 + xsd:integer(substr(str(?sdE), 15, 2)) as ?sminE)
bind(coalesce(xsd:integer(substr(str(?edE), 12, 2)) * 60 + xsd:integer(substr(str(?edE), 15, 2)), ?sminE + 30) as ?eminE)
bind(coalesce(str(?lbE), "(untitled)") as ?tlabelE) } }
{ select distinct ?dayF ?r3 where {
graph npa:graph {
?npF npa:hasValidSignatureForPublicKeyHash ?pkF ;
np:hasAssertion ?ae2 ; npx:introduces ?e2 ; dct:created ?crF .
filter not exists { ?invF npx:invalidates ?npF ; npa:hasValidSignatureForPublicKeyHash ?pkF . }
filter not exists { ?npF npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwF npx:introduces ?e2 ; npa:hasValidSignatureForPublicKeyHash ?pkwF ; dct:created ?crwF .
filter(?crwF > ?crF)
filter not exists { ?invwF npx:invalidates ?nwF ; npa:hasValidSignatureForPublicKeyHash ?pkwF . }
filter not exists { ?nwF npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgF { ?newerF npx:supersedes ?npF . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evF)
} union {
values ?_resource_multi_iri {}
graph ?mgF { ?_resource_multi_iri gen:isMaintainedBy ?evF }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kinde2 ?rele2 ?pathF ?fillF ?strokeF) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?ae2 { ?e2 a ?kinde2 ; ?rele2 ?evF . }
optional { graph ?ae2 { ?e2 schema:startDate ?sdAF } }
optional { graph ?ae2 { ?e2 schemaold:startDate ?sdBF } }
optional { graph ?ae2 { ?e2 schema:endDate ?edAF } }
optional { graph ?ae2 { ?e2 schemaold:endDate ?edBF } }
optional { graph ?ae2 { ?e2 schema:location ?loAF } }
optional { graph ?ae2 { ?e2 schemaold:location ?loBF } }
optional { graph ?ae2 { ?e2 rdfs:label ?lbF } }
bind(coalesce(?sdAF, ?sdBF) as ?sdF)
filter(bound(?sdF))
bind(coalesce(?edAF, ?edBF) as ?edF)
bind(coalesce(str(?loAF), str(?loBF), "") as ?r3)
bind(substr(str(?sdF), 1, 10) as ?dayF)
bind(xsd:integer(substr(str(?sdF), 12, 2)) * 60 + xsd:integer(substr(str(?sdF), 15, 2)) as ?sminF)
bind(coalesce(xsd:integer(substr(str(?edF), 12, 2)) * 60 + xsd:integer(substr(str(?edF), 15, 2)), ?sminF + 30) as ?eminF)
bind(coalesce(str(?lbF), "(untitled)") as ?tlabelF) } }
filter(?dayF = ?day)
} group by ?day ?room
}
bind(30 + ?hcol * 66 as ?ly)
# The label column is 104 units wide, which is 14 characters at font-size 11,
# whose widest character is 6.83px, and 17 at font-size 9 (5.59px): a room name
# too long for one line of the larger size goes onto two of the smaller.
bind("^(.{0,17})\\s.*$" as ?hwrapx)
bind(replace(?room, ?hwrapx, "$1") as ?hd1raw)
bind(if(strlen(?room) <= 17, ?room,
if(strlen(?hd1raw) > 17, substr(?hd1raw, 1, 17), ?hd1raw)) as ?hd1)
bind(if(strlen(?room) > strlen(?hd1),
substr(?room, strlen(?hd1) + if(substr(?room, strlen(?hd1) + 1, 1) = " ", 2, 1)), "") as ?hd2raw)
bind(if(strlen(?hd2raw) > 17, concat(substr(?hd2raw, 1, 16), "…"), ?hd2raw) as ?hd2)
bind(concat(
'<rect x="0" y="', str(?ly), '" width="104" height="60" rx="3" fill="#1d3d5c"></rect>',
if(strlen(?room) <= 14,
concat('<text x="52" y="', str(?ly + 34), '" text-anchor="middle" font-size="11" font-weight="bold" fill="#ffffff">',
replace(replace(replace(?room, "&", "&"), "<", "<"), ">", ">"), '</text>'),
concat('<text x="52" y="', str(?ly + 28), '" text-anchor="middle" font-size="9" font-weight="bold" fill="#ffffff">',
replace(replace(replace(?hd1, "&", "&"), "<", "<"), ">", ">"), '</text>',
'<text x="52" y="', str(?ly + 40), '" text-anchor="middle" font-size="9" font-weight="bold" fill="#ffffff">',
replace(replace(replace(?hd2, "&", "&"), "<", "<"), ">", ">"), '</text>'))) as ?frag)
}
}
union
# ============ the clock along the top and the bottom ============
{
select ?day ?frag (?ybase + 20 as ?ybot) (?hx + 20 as ?xright)
where {
{
select ?day (min(?smin) as ?first) (max(?emin) as ?last) (count(distinct ?roomT) as ?nrow) where {
graph npa:graph {
?npT npa:hasValidSignatureForPublicKeyHash ?pkT ;
np:hasAssertion ?at1 ; npx:introduces ?t1 ; dct:created ?crT .
filter not exists { ?invT npx:invalidates ?npT ; npa:hasValidSignatureForPublicKeyHash ?pkT . }
filter not exists { ?npT npx:hasNanopubType npx:ExampleNanopub . }
# latest-wins across signing keys: an override by another admin carries no npx:supersedes
filter not exists {
?nwT npx:introduces ?t1 ; npa:hasValidSignatureForPublicKeyHash ?pkwT ; dct:created ?crwT .
filter(?crwT > ?crT)
filter not exists { ?invwT npx:invalidates ?nwT ; npa:hasValidSignatureForPublicKeyHash ?pkwT . }
filter not exists { ?nwT npx:hasNanopubType npx:ExampleNanopub . }
}
}
filter not exists { graph ?sgT { ?newerT npx:supersedes ?npT . } }
{
values ?_resource_multi_iri {}
bind(?_resource_multi_iri as ?evT)
} union {
values ?_resource_multi_iri {}
graph ?mgT { ?_resource_multi_iri gen:isMaintainedBy ?evT }
}
# one pattern over a kind table instead of a union per kind: each union branch
# re-ran the whole join, and this block is repeated ten times
values (?kindt1 ?relt1 ?pathT ?fillT ?strokeT) {
(wd:Q604733 dct:isPartOf "/part?id=" "#eaf1f8" "#9bb4cc")
(conf:Workshop gen:isSubSpaceOf "/space?id=" "#fdf0e2" "#d9a55f")
(conf:Tutorial gen:isSubSpaceOf "/space?id=" "#eef7ec" "#8fbf86")
(conf:Session gen:isSubSpaceOf "/space?id=" "#f1ecf8" "#a58fc8")
}
graph ?at1 { ?t1 a ?kindt1 ; ?relt1 ?evT . }
optional { graph ?at1 { ?t1 schema:startDate ?sdAT } }
optional { graph ?at1 { ?t1 schemaold:startDate ?sdBT } }
optional { graph ?at1 { ?t1 schema:endDate ?edAT } }
optional { graph ?at1 { ?t1 schemaold:endDate ?edBT } }
optional { graph ?at1 { ?t1 schema:location ?loAT } }
optional { graph ?at1 { ?t1 schemaold:location ?loBT } }
optional { graph ?at1 { ?t1 rdfs:label ?lbT } }
bind(coalesce(?sdAT, ?sdBT) as ?sdT)
filter(bound(?sdT))
bind(coalesce(?edAT, ?edBT) as ?edT)
bind(coalesce(str(?loAT), str(?loBT), "") as ?roomT)
bind(substr(str(?sdT), 1, 10) as ?day)
bind(xsd:integer(substr(str(?sdT), 12, 2)) * 60 + xsd:integer(substr(str(?sdT), 15, 2)) as ?smin)
bind(coalesce(xsd:integer(substr(str(?edT), 12, 2)) * 60 + xsd:integer(substr(str(?edT), 15, 2)), ?smin + 30) as ?emin)
bind(coalesce(str(?lbT), "(untitled)") as ?tlabelT)
} group by ?day
}
values ?hr { 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 }
bind(if(?last > ?first, ?last - ?first, 1) as ?hspan)
bind(if(1140 / ?hspan < 6.0, floor(114000 / ?hspan) / 100, 6.0) as ?ppm)
filter(?hr * 60 >= ?first && ?hr * 60 <= ?last)
bind(112 + xsd:integer(floor((?hr * 60 - ?first) * ?ppm)) as ?hx)
# The clock is written along the top and the bottom of the lanes rather than
# ruled through them: a line through a box would cross its title, and the boxes
# carry their own times. The room count comes free from the same aggregate.
bind(24 + ?nrow * 66 as ?ybase)
bind(concat(if(?hr < 10, concat("0", str(?hr)), str(?hr)), ':00') as ?hlabel)
bind(concat(
'<text x="', str(?hx), '" y="18" text-anchor="middle" font-size="10" fill="#6b7c8d">', ?hlabel, '</text>',
'<line x1="', str(?hx), '" y1="22" x2="', str(?hx), '" y2="28" stroke="#b9c6d2"></line>',
'<line x1="', str(?hx), '" y1="', str(?ybase), '" x2="', str(?hx), '" y2="', str(?ybase + 6),
'" stroke="#b9c6d2"></line>',
'<text x="', str(?hx), '" y="', str(?ybase + 18), '" text-anchor="middle" font-size="10" fill="#6b7c8d">',
?hlabel, '</text>') as ?frag)
}
}
} group by ?day
}
bind(?day as ?title)
bind(?maxx + 8 as ?w)
bind(?maxy + 16 as ?h)
}
order by ?title
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/provenance
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/assertion
http://www.w3.org/ns/prov#wasAttributedTo
https://orcid.org/0000-0002-1267-0234
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/pubinfo
https://orcid.org/0000-0002-1267-0234
http://xmlns.com/foaf/0.1/name
Tobias Kuhn
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://purl.org/dc/terms/created
2026-10-10T09:29:47Z
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://purl.org/dc/terms/creator
https://orcid.org/0000-0002-1267-0234
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://purl.org/dc/terms/license
https://creativecommons.org/licenses/by/4.0/
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://purl.org/nanopub/x/embeds
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/get-presentations-rooms-svg
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
http://www.w3.org/2000/01/rdf-schema#label
Get the schedule of an event as SVG room lanes
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromProvenanceTemplate
http://purl.org/np/RANwQa4ICWS5SOjw7gp99nBpXBasapwtZF1fIM3H2gYTM
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromPubinfoTemplate
https://w3id.org/np/RA-N4_kFxcruvBTlo1yJv29E4SLOXsx5KO_th69PprMrA
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromPubinfoTemplate
https://w3id.org/np/RACJ58Gvyn91LqCKIO9zu1eijDQIeEff28iyDrJgjSJF8
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromPubinfoTemplate
https://w3id.org/np/RARJj78P72NR5edKOnu_f4ePE9NYYuW2m2pM-fEoobMBk
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromPubinfoTemplate
https://w3id.org/np/RAoTD7udB2KtUuOuAe74tJi1t3VzK0DyWS7rYVAq1GRvw
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/o/ntemplate/wasCreatedFromTemplate
https://w3id.org/np/RAEFAt-QcFK0ZhqfvlsmS10BnzGJA0xwOICZXkO-ai87k
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/sig
http://purl.org/nanopub/x/hasAlgorithm
RSA
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/sig
http://purl.org/nanopub/x/hasPublicKey
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/sig
http://purl.org/nanopub/x/hasSignature
W4VacbGOjR8LExKvomL2xDyrlGUUQeW/kSK1V+RIiKJbQqFerF1h0oQmetLUB/CGJqXksPNPgLQ76uAM2LnuvAtUmJnjXobOX2IALov+6jqCqao3yL/RwQHYwDEISQBnYwd79xyyW4C3vpIChdvcFBIkTmK3BGRo0yXF6IgAi4I=
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/sig
http://purl.org/nanopub/x/hasSignatureTarget
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ
https://w3id.org/np/RACEVIJeWKzHw82z_MxXym5iOvLwUy7HVq69C8X7Rc3JQ/sig
http://purl.org/nanopub/x/signedBy
https://orcid.org/0000-0002-1267-0234