| @@ -0,0 +1,13 @@ | |||
| AddType application/ld+json .jsonld | |||
| Header set Access-Control-Allow-Origin * | |||
| RewriteEngine On | |||
| RewriteBase /statistics/ | |||
| RewriteRule ^by-period/$ byPeriodDataset.php | |||
| RewriteRule ^by-period/(.*)/(.*) byPeriodSlice.php?date-start=$1&date-end=$2 [B] | |||
| RewriteRule ^sender/(.*) sender.php?hash=$1 [B] | |||
| RewriteRule ^$ doc/ [L,R=301] | |||
| RewriteRule ^(key|structure)/ structures.jsonld [L,R=303] | |||
| RewriteRule ^property/ properties.jsonld [L,R=303] | |||
| @@ -0,0 +1,49 @@ | |||
| <?php | |||
| require_once 'common.php'; | |||
| // load document with month statistics | |||
| try { | |||
| $document = load_remote_dom_document('https://wandystan.groups.io/g/wandystan/months'); | |||
| } catch (Exception $e) { | |||
| exit_error($e->getMessage()); | |||
| } | |||
| $xpath = new DOMXPath($document); | |||
| // find all months with non-zero number of posts | |||
| $months = []; | |||
| $rows = $xpath->query('//table/tbody/tr'); | |||
| foreach ($rows as $row) { | |||
| $cols = $xpath->query('td', $row); | |||
| $year = $cols[0]->nodeValue; | |||
| for ($i = 1; $i < $cols->length; $i++) { | |||
| if ( | |||
| $cols[$i]->firstChild->nodeType === XML_ELEMENT_NODE && | |||
| $cols[$i]->firstChild->tagName === 'a' | |||
| ) { | |||
| $months []= $year . '-' . str_pad($i, 2, '0', STR_PAD_LEFT); | |||
| } | |||
| } | |||
| } | |||
| // construct a linked data object corresponding to gathered data | |||
| $ld = [ | |||
| '@context' => 'https://wandystan.eu/statistics/context.jsonld', | |||
| '@type' => 'DataSet', | |||
| 'title' => [ | |||
| 'en' => 'Posts by date and sender', | |||
| 'pl' => 'Wiadomości wg daty i wysyłającego' | |||
| ], | |||
| 'description' => [ | |||
| 'en' => 'Statistics of number of posts sent by a given sender on a given date, grouped by period in which they were sent.', | |||
| 'pl' => 'Statystyki liczby wiadomości wysłanych przez danego wysyłającego w danym dniu, pogrupowane wg okresu w jakim zostały wysłane.' | |||
| ], | |||
| 'publisher' => 'https://wandystan.eu/', | |||
| 'structure' => 'structure/by-period', | |||
| 'slices' => array_map(function ($month) { return "by-period/$month-01/P1M"; }, $months) | |||
| ]; | |||
| header('Content-type: application/ld+json'); | |||
| print json_encode($ld); | |||
| @@ -0,0 +1,110 @@ | |||
| <?php | |||
| require_once 'common.php'; | |||
| // get request data and validate it | |||
| $param_date_start = $_GET['date-start']; | |||
| $param_date_end = $_GET['date-end']; | |||
| if (! $param_date_start) { | |||
| exit_error('No start date specified.'); | |||
| } elseif (! $param_date_end) { | |||
| exit_error('No end date specified.'); | |||
| } elseif (! mb_ereg_match('^' . REGEXP_ISO8601_DATE_OR_INTERVAL . '$', $param_date_start)) { | |||
| exit_error('Invalid start date.'); | |||
| } elseif (! mb_ereg_match('^' . REGEXP_ISO8601_DATE_OR_INTERVAL . '$', $param_date_end)) { | |||
| exit_error('Invalid end date.'); | |||
| } elseif (starts_with($param_date_start, 'P') && starts_with($param_date_end, 'P')) { | |||
| exit_error('Both start and end dates cannot be periods.'); | |||
| } | |||
| // create start and end date objects | |||
| $tz = new DateTimeZone('UTC'); | |||
| try { | |||
| if (! starts_with($param_date_start, 'P')) | |||
| $date_start = new DateTimeImmutable($param_date_start, $tz); | |||
| if (! starts_with($param_date_end, 'P')) | |||
| $date_end = new DateTimeImmutable($param_date_end, $tz); | |||
| if (starts_with($param_date_start, 'P')) { | |||
| $interval = new DateInterval($param_date_start); | |||
| $date_start = $date_end->sub($interval); | |||
| } | |||
| if (starts_with($param_date_end, 'P')) { | |||
| $interval = new DateInterval($param_date_end); | |||
| $date_end = $date_start->add($interval); | |||
| } | |||
| } catch (Exception $e) { | |||
| exit_error('Invalid date specification: ' . $e->getMessage()); | |||
| } | |||
| // get page with the search results for the given period | |||
| try { | |||
| $document = load_remote_dom_document('https://wandystan.groups.io/g/wandystan/search?p=Created,,,10000,2,0,0&d=6&startdate=' . $date_start->format('m/d/Y') . '&enddate=' . $date_end->modify('-1 second')->format('m/d/Y')); | |||
| } catch (Exception $e) { | |||
| exit_error($e->getMessage()); | |||
| } | |||
| $xpath = new DOMXPath($document); | |||
| // find all messages in search results and summarise them | |||
| $messages = $xpath->query('//div[@id = "maincontent"]/table//td[span[@class = "subject"]]'); | |||
| $summary = []; | |||
| foreach ($messages as $message) { | |||
| $sender = trim($xpath->evaluate('substring-before(substring-after(normalize-space(div[@class = "hidden-xs"]/following-sibling::text()[1]), "By "), " · #")', $message), '"'); | |||
| $timestamp = $xpath->evaluate('substring-before(substring-after(.//script[@class = "timedisp"], "DisplayShortTime( "), " ,")', $message); | |||
| $date = new DateTime(null, $tz); | |||
| $date->setTimestamp($timestamp / 1000000000); | |||
| $key = serialize([ | |||
| 'date' => $date->format('Y-m-d'), | |||
| 'sender' => $sender | |||
| ]); | |||
| $summary[$key]++; | |||
| } | |||
| // construct a linked data object corresponding to gathered data | |||
| $ld = [ | |||
| '@context' => 'https://wandystan.eu/statistics/context.jsonld', | |||
| '@type' => 'Slice', | |||
| 'key' => 'key/by-period', | |||
| 'period' => [ | |||
| '@type' => 'Interval', | |||
| 'hasBeginning' => [ | |||
| '@type' => 'Instant', | |||
| 'timestamp' => $date_start->format(DATE_ATOM) | |||
| ], | |||
| 'hasEnd' => [ | |||
| '@type' => 'Instant', | |||
| 'timestamp' => $date_end->format(DATE_ATOM) | |||
| ] | |||
| ] | |||
| ]; | |||
| $observations = []; | |||
| foreach ($summary as $key => $entry) { | |||
| $key = unserialize($key); | |||
| $nameHash = hash('fnv1a32', $key['sender']); | |||
| $observations []= [ | |||
| '@id' => 'by-period/' . $key['date'] . '/P1D#' . $nameHash, | |||
| '@type' => 'Observation', | |||
| 'dataset' => "by-period/", | |||
| 'date' => $key['date'], | |||
| 'sender' => [ | |||
| '@id' => 'sender/' . $nameHash, | |||
| '@type' => 'Agent', | |||
| 'name' => $key['sender'], | |||
| 'name_fnv1a32sum' => $nameHash | |||
| ], | |||
| 'posts' => $entry | |||
| ]; | |||
| } | |||
| $ld['observations'] = $observations; | |||
| header('Content-type: application/ld+json'); | |||
| print json_encode($ld); | |||
| @@ -0,0 +1,33 @@ | |||
| <?php | |||
| define('REGEXP_ISO8601_DATE', '\d{4}(-\d{2}|-?(\d{2}-?\d{2}|W\d{2}(-\d)?|\d{3}))'); | |||
| define('REGEXP_ISO8601_INTERVAL', 'P(\d+Y(\d+M)?(\d+D)?|\d+M(\d+D)?|\d+[DW])'); | |||
| define('REGEXP_ISO8601_DATE_OR_INTERVAL', '(' . REGEXP_ISO8601_DATE . '|' . REGEXP_ISO8601_INTERVAL . ')'); | |||
| function exit_error($message) { | |||
| http_response_code(500); | |||
| header('Content-type: text/plain; charset=utf-8'); | |||
| print 'ERROR: ' . $message . PHP_EOL; | |||
| exit; | |||
| } | |||
| function exit_error_handler($exception) { | |||
| exit_error($exception->getMessage()); | |||
| } | |||
| set_exception_handler('exit_error_handler'); | |||
| function load_remote_dom_document($uri) { | |||
| $content = file_get_contents($uri); | |||
| $document = new DOMDocument; | |||
| if ($content === false) | |||
| throw new Exception("Cannot load remote URI: $uri"); | |||
| if (! $document->loadHTML($content, LIBXML_NOWARNING | LIBXML_NOERROR)) | |||
| throw new Exception("Cannot parse remote URI as HTML: $uri"); | |||
| return $document; | |||
| } | |||
| function starts_with($haystack, $needle) { | |||
| return substr_compare($haystack, $needle, 0, strlen($needle)) === 0; | |||
| } | |||
| @@ -0,0 +1,106 @@ | |||
| { | |||
| "@context": { | |||
| "@base": "https://wandystan.eu/statistics/", | |||
| "@vocab": "http://purl.org/linked-data/cube#", | |||
| "dcterms": "http://purl.org/dc/terms/", | |||
| "foaf": "http://xmlns.com/foaf/0.1/", | |||
| "prop": "https://wandystan.eu/statistics/property/", | |||
| "rdfs": "http://www.w3.org/2000/01/rdf-schema#", | |||
| "time": "http://www.w3.org/2006/time#", | |||
| "xsd": "http://www.w3.org/2001/XMLSchema#", | |||
| "Agent": "foaf:Agent", | |||
| "Instant": "time:Instant", | |||
| "Interval": "time:Interval", | |||
| "comment": { | |||
| "@id": "rdfs:comment", | |||
| "@container": "@language" | |||
| }, | |||
| "componentAttachment": { | |||
| "@type": "@vocab" | |||
| }, | |||
| "componentProperty": { | |||
| "@type": "@vocab" | |||
| }, | |||
| "dataset": { | |||
| "@id": "dataSet", | |||
| "@type": "@id" | |||
| }, | |||
| "date": { | |||
| "@id": "prop:date", | |||
| "@type": "xsd:date" | |||
| }, | |||
| "description": { | |||
| "@id": "dcterms:description", | |||
| "@container": "@language" | |||
| }, | |||
| "dimension": { | |||
| "@type": "@id" | |||
| }, | |||
| "hasBeginning": { | |||
| "@id": "time:hasBeginning", | |||
| "@type": "@id" | |||
| }, | |||
| "hasEnd": { | |||
| "@id": "time:hasEnd", | |||
| "@type": "@id" | |||
| }, | |||
| "issued": { | |||
| "@id": "dcterms:issued", | |||
| "@type": "xsd:date" | |||
| }, | |||
| "key": { | |||
| "@id": "sliceStructure", | |||
| "@type": "@id" | |||
| }, | |||
| "label": { | |||
| "@id": "rdfs:label", | |||
| "@container": "@language" | |||
| }, | |||
| "measure": { | |||
| "@type": "@id" | |||
| }, | |||
| "name": "foaf:name", | |||
| "name_fnv1a32sum": { | |||
| "@id": "prop:name_fnv1a32sum", | |||
| "@type": "xsd:hexBinary" | |||
| }, | |||
| "observations": "observation", | |||
| "period": { | |||
| "@id": "prop:period", | |||
| "@type": "prop:ISO8601-1" | |||
| }, | |||
| "posts": { | |||
| "@id": "prop:posts", | |||
| "@type": "xsd:nonNegativeInteger" | |||
| }, | |||
| "publisher": { | |||
| "@id": "dcterms:publisher", | |||
| "@type": "@id" | |||
| }, | |||
| "sender": "prop:sender", | |||
| "sliceKey": { | |||
| "@type": "@id" | |||
| }, | |||
| "slices": { | |||
| "@id": "slice", | |||
| "@type": "@id" | |||
| }, | |||
| "structure": { | |||
| "@id": "structure", | |||
| "@type": "@id" | |||
| }, | |||
| "subject": { | |||
| "@id": "dcterms:subject", | |||
| "@type": "@id" | |||
| }, | |||
| "timestamp": { | |||
| "@id": "time:inXSDDateTimeStamp", | |||
| "@type": "xsd:dateTimeStamp" | |||
| }, | |||
| "title": { | |||
| "@id": "dcterms:title", | |||
| "@container": "@language" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,2 @@ | |||
| index.html: index.markdown | |||
| pandoc -s -c style.css -M lang=pl --shift-heading-level-by 1 -o $@ $< | |||
| @@ -0,0 +1 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/><path d="M0 0h24v24H0z" fill="none"/></svg> | |||
| @@ -0,0 +1 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z"/><path d="M0 0h24v24H0z" fill="none"/></svg> | |||
| @@ -0,0 +1,87 @@ | |||
| <!DOCTYPE html> | |||
| <html xmlns="http://www.w3.org/1999/xhtml" lang="pl" xml:lang="pl"> | |||
| <head> | |||
| <meta charset="utf-8" /> | |||
| <meta name="generator" content="pandoc" /> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" /> | |||
| <meta name="author" content="Polyna" /> | |||
| <meta name="dcterms.date" content="2020-03-12" /> | |||
| <title>Statystyki Listy Dyskusyjnej Mandragoratu Wandystanu</title> | |||
| <style> | |||
| code{white-space: pre-wrap;} | |||
| span.smallcaps{font-variant: small-caps;} | |||
| span.underline{text-decoration: underline;} | |||
| div.column{display: inline-block; vertical-align: top; width: 50%;} | |||
| div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} | |||
| ul.task-list{list-style: none;} | |||
| </style> | |||
| <link rel="stylesheet" href="style.css" /> | |||
| <!--[if lt IE 9]> | |||
| <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script> | |||
| <![endif]--> | |||
| </head> | |||
| <body> | |||
| <header id="title-block-header"> | |||
| <h1 class="title">Statystyki Listy Dyskusyjnej Mandragoratu Wandystanu</h1> | |||
| <p class="author"><a href="/w/profile,196">Polyna</a></p> | |||
| <p class="date">2020-03-12</p> | |||
| </header> | |||
| <p>Statystyki <a href="https://wandystan.groups.io/g/wandystan/">Listy Dyskusyjnej Mandragoratu Wandystanu</a> są udostępniane jako dane połączone, przy użyciu słownictwa <a href="https://www.w3.org/TR/vocab-data-cube/" lang="en">RDF Data Cube</a>. Zapisane są one w postaci <a href="https://json-ld.org/" lang="en"><img src="icon-json-ld.png" style="vertical-align:bottom" /> JSON-LD</a> z <a href="../context.jsonld">odpowiednim kontekstem</a>, i mogą być przetwarzane zarówno za pomocą narzędzi przeznaczonych dla JSON-LD, jak i bezpośrednio, tak jak zwykłe dokumenty <a href="https://pl.wikipedia.org/wiki/JSON">JSON</a>.</p> | |||
| <p>Wszystkie odnośniki podane w postaci względnej posiadają podstawę <a href="../"><code>https://wandystan.eu/statistics/</code></a> – przykładowo, <code>"key": "key/by-period"</code> oznacza odnośnik do adresu <a href="../key/by-period"><code>https://wandystan.eu/statistics/key/by-period</code></a>.</p> | |||
| <p>Udostępniane są następujące rodzaje danych:</p> | |||
| <h2 id="wiadomości-wg-daty-i-wysyłającego">Wiadomości wg daty i wysyłającego</h2> | |||
| <p>Statystyki liczby wiadomości wysłanych przez danego wysyłającego w danym dniu, pogrupowane wg okresu w jakim zostały wysłane.</p> | |||
| <p>Ze względu na ogromną ilość udostępnianych danych, statystyki podzielone są na wiele dokumentów:</p> | |||
| <h3 id="zbiór-danych">Zbiór danych</h3> | |||
| <p>Dokument opisujący udostępniany zbiór danych wraz z odnośnikami do jego wycinków obejmujących okres pojedynczego miesiąca.</p> | |||
| <p>Adres dokumentu: <a href="../by-period/"><code>https://wandystan.eu/statistics/by-period/</code></a>.</p> | |||
| <p>Układ dokumentu:</p> | |||
| <ul> | |||
| <li><code>@type</code> – rodzaj obiektu: zbiór danych statystycznych.</li> | |||
| <li><code>title</code> – tytuł zbioru danych; obiekt którego kluczami są kody języków, a wartościami – tytuł zapisany w tym języku.</li> | |||
| <li><code>description</code> – opis zbioru danych; obiekt którego kluczami są kody języków, a wartościami – opis zapisany w tym języku.</li> | |||
| <li><code>publisher</code> – odnośnik do wydawcy dokumentu.</li> | |||
| <li><code>structure</code> – odnośnik do formalnego opisu układu danych statystycznych.</li> | |||
| <li><code>slices</code> – tablica odnośników do wycinków zbioru danych obejmujących okres pojedynczego miesiąca.</li> | |||
| </ul> | |||
| <h3 id="wycinki-danych">Wycinki danych</h3> | |||
| <p>Dokumenty zawierające dane statystyczne z wybranego okresu.</p> | |||
| <p>Adres dokumentu: <code>https://wandystan.eu/statistics/by-period/<var>⟨przedział⟩</var></code>; gdzie <code><var>⟨przedział⟩</var></code> to przedział dat w zapisie <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>, z podaną co najmniej jedną datą początkową lub/i jedną datą końcową, bez podanego czasu. Data początkowa jest zawsze uznawana jako zawierająca się w danym okresie, zaś data końcowa jako niezawierająca się. Przykłady poprawnie zapisanych przedziałów:</p> | |||
| <ul> | |||
| <li><code>2018-12-11/2019-04-21</code> – okres od 11 grudnia 2018 r. (włącznie) do 21 kwietnia 2019 r. (wyłącznie).</li> | |||
| <li><code>2020-02/P1M</code> – cały luty 2020 r.</li> | |||
| <li><code>P2M5D/2020-W03</code> – 2 miesiące i 5 dni poprzedzające trzeci tydzień 2020 r.</li> | |||
| </ul> | |||
| <p>Jeżeli w podanym przedziale napisano więcej niż 10 000 wiadomości, pod uwagę brane będą tylko te najpóźniej wysłane, więc nie jest zalecane podawanie zbyt długich przedziałów.</p> | |||
| <p>Układ dokumentu:</p> | |||
| <ul> | |||
| <li><code>@type</code> – rodzaj obiektu: wycinek zbioru danych statystycznych.</li> | |||
| <li><code>key</code> – odnośnik do klucza danych wycinka.</li> | |||
| <li><code>period</code> – okres, którego dotyczy dany wycinek. | |||
| <ul> | |||
| <li><code>@type</code> – rodzaj obiektu: przedział czasu.</li> | |||
| <li><code>hasBeginning</code> – początek przedziału czasu. | |||
| <ul> | |||
| <li><code>@type</code> – rodzaj obiektu: chwila w czasie.</li> | |||
| <li><code>timestamp</code> – znacznik czasu w zapisie <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>.</li> | |||
| </ul></li> | |||
| <li><code>hasEnd</code> – koniec przedziału czasu; obiekt o takim samym układzie co <code>hasBeginning</code>.</li> | |||
| </ul></li> | |||
| <li><code>observations</code> – poszczególne dane jednostkowe (spostrzeżenia) dotyczące danego okresu – tablica obiektów o następującej strukturze: | |||
| <ul> | |||
| <li><code>@id</code> – oznaczenie przypisane do danego spostrzeżenia.</li> | |||
| <li><code>@type</code> – rodzaj obiektu: dana jednostkowa (spostrzeżenie).</li> | |||
| <li><code>dataset</code> – odnośnik do zbioru, do którego przypisana jest dana.</li> | |||
| <li><code>date</code> – dzień w którym zostały wysłane wiadomości na listę, w zapisie <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>.</li> | |||
| <li><code>sender</code> – wysyłający wiadomości na listę w danym dniu. | |||
| <ul> | |||
| <li><code>@id</code> – oznaczenie przypisane do danego wysyłającego.</li> | |||
| <li><code>@type</code> – rodzaj obiektu: osoba bądź inna jednostka (organizacja, program samoczynnie wysyłający wiadomości, itp.) mająca możliwość podejmowania działań.</li> | |||
| <li><code>name</code> – nazwa tej osoby bądź jednostki.</li> | |||
| <li><code>name_fnv1a32sum</code> – skrót nazwy utworzony za pomocą <a href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function">algorytmu FNV-1a</a> w odmianie 32-bitowej, zapisany w postaci szesnastkowej. Może być przekształcony w równoważny ciąg bitów, bądź 32-bitową liczbę bez znaku.</li> | |||
| </ul></li> | |||
| <li><code>posts</code> – ilość postów wysłanych na listę przez danego wysyłającego w danym dniu.</li> | |||
| </ul></li> | |||
| </ul> | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,67 @@ | |||
| % Statystyki Listy Dyskusyjnej Mandragoratu Wandystanu | |||
| % [Polyna](/w/profile,196) | |||
| % 2020-03-12 | |||
| Statystyki [Listy Dyskusyjnej Mandragoratu Wandystanu](https://wandystan.groups.io/g/wandystan/) są udostępniane jako dane połączone, przy użyciu słownictwa [RDF Data Cube](https://www.w3.org/TR/vocab-data-cube/){lang=en}. Zapisane są one w postaci [{style=vertical-align:bottom} JSON-LD](https://json-ld.org/){lang=en} z [odpowiednim kontekstem](../context.jsonld), i mogą być przetwarzane zarówno za pomocą narzędzi przeznaczonych dla JSON-LD, jak i bezpośrednio, tak jak zwykłe dokumenty [JSON](https://pl.wikipedia.org/wiki/JSON). | |||
| Wszystkie odnośniki podane w postaci względnej posiadają podstawę [`https://wandystan.eu/statistics/`](../) – przykładowo, `"key": "key/by-period"` oznacza odnośnik do adresu [`https://wandystan.eu/statistics/key/by-period`](../key/by-period). | |||
| Udostępniane są następujące rodzaje danych: | |||
| Wiadomości wg daty i wysyłającego | |||
| ================================= | |||
| Statystyki liczby wiadomości wysłanych przez danego wysyłającego w danym dniu, pogrupowane wg okresu w jakim zostały wysłane. | |||
| Ze względu na ogromną ilość udostępnianych danych, statystyki podzielone są na wiele dokumentów: | |||
| Zbiór danych | |||
| ------------ | |||
| Dokument opisujący udostępniany zbiór danych wraz z odnośnikami do jego wycinków obejmujących okres pojedynczego miesiąca. | |||
| Adres dokumentu: [`https://wandystan.eu/statistics/by-period/`](../by-period/). | |||
| Układ dokumentu: | |||
| * `@type` – rodzaj obiektu: zbiór danych statystycznych. | |||
| * `title` – tytuł zbioru danych; obiekt którego kluczami są kody języków, a wartościami – tytuł zapisany w tym języku. | |||
| * `description` – opis zbioru danych; obiekt którego kluczami są kody języków, a wartościami – opis zapisany w tym języku. | |||
| * `publisher` – odnośnik do wydawcy dokumentu. | |||
| * `structure` – odnośnik do formalnego opisu układu danych statystycznych. | |||
| * `slices` – tablica odnośników do wycinków zbioru danych obejmujących okres pojedynczego miesiąca. | |||
| Wycinki danych | |||
| -------------- | |||
| Dokumenty zawierające dane statystyczne z wybranego okresu. | |||
| Adres dokumentu: <code>https://wandystan.eu/statistics/by-period/<var>⟨przedział⟩</var></code>; gdzie <code><var>⟨przedział⟩</var></code> to przedział dat w zapisie [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), z podaną co najmniej jedną datą początkową lub/i jedną datą końcową, bez podanego czasu. Data początkowa jest zawsze uznawana jako zawierająca się w danym okresie, zaś data końcowa jako niezawierająca się. Przykłady poprawnie zapisanych przedziałów: | |||
| * `2018-12-11/2019-04-21` – okres od 11 grudnia 2018 r. (włącznie) do 21 kwietnia 2019 r. (wyłącznie). | |||
| * `2020-02/P1M` – cały luty 2020 r. | |||
| * `P2M5D/2020-W03` – 2 miesiące i 5 dni poprzedzające trzeci tydzień 2020 r. | |||
| Jeżeli w podanym przedziale napisano więcej niż 10 000 wiadomości, pod uwagę brane będą tylko te najpóźniej wysłane, więc nie jest zalecane podawanie zbyt długich przedziałów. | |||
| Układ dokumentu: | |||
| * `@type` – rodzaj obiektu: wycinek zbioru danych statystycznych. | |||
| * `key` – odnośnik do klucza danych wycinka. | |||
| * `period` – okres, którego dotyczy dany wycinek. | |||
| * `@type` – rodzaj obiektu: przedział czasu. | |||
| * `hasBeginning` – początek przedziału czasu. | |||
| * `@type` – rodzaj obiektu: chwila w czasie. | |||
| * `timestamp` – znacznik czasu w zapisie [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). | |||
| * `hasEnd` – koniec przedziału czasu; obiekt o takim samym układzie co `hasBeginning`. | |||
| * `observations` – poszczególne dane jednostkowe (spostrzeżenia) dotyczące danego okresu – tablica obiektów o następującej strukturze: | |||
| * `@id` – oznaczenie przypisane do danego spostrzeżenia. | |||
| * `@type` – rodzaj obiektu: dana jednostkowa (spostrzeżenie). | |||
| * `dataset` – odnośnik do zbioru, do którego przypisana jest dana. | |||
| * `date` – dzień w którym zostały wysłane wiadomości na listę, w zapisie [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). | |||
| * `sender` – wysyłający wiadomości na listę w danym dniu. | |||
| * `@id` – oznaczenie przypisane do danego wysyłającego. | |||
| * `@type` – rodzaj obiektu: osoba bądź inna jednostka (organizacja, program samoczynnie wysyłający wiadomości, itp.) mająca możliwość podejmowania działań. | |||
| * `name` – nazwa tej osoby bądź jednostki. | |||
| * `name_fnv1a32sum` – skrót nazwy utworzony za pomocą [algorytmu FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) w odmianie 32-bitowej, zapisany w postaci szesnastkowej. Może być przekształcony w równoważny ciąg bitów, bądź 32-bitową liczbę bez znaku. | |||
| * `posts` – ilość postów wysłanych na listę przez danego wysyłającego w danym dniu. | |||
| @@ -0,0 +1,15 @@ | |||
| body { | |||
| width: 50em; | |||
| font-family: sans-serif; | |||
| line-height: 1.5; | |||
| } | |||
| .author { | |||
| padding-left: 2em; | |||
| background: url('icon-author.svg') left center / contain no-repeat; | |||
| } | |||
| .date { | |||
| padding-left: 2em; | |||
| background: url('icon-date.svg') left center / contain no-repeat; | |||
| } | |||
| @@ -0,0 +1,104 @@ | |||
| { | |||
| "@context": { | |||
| "@language": "en", | |||
| "dct": "http://purl.org/dc/terms/", | |||
| "owl": "http://www.w3.org/2002/07/owl#", | |||
| "prop": "https://wandystan.eu/statistics/property/", | |||
| "qb": "http://purl.org/linked-data/cube#", | |||
| "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", | |||
| "rdfs": "http://www.w3.org/2000/01/rdf-schema#", | |||
| "sdmx-concept": "http://purl.org/linked-data/sdmx/2009/concept#", | |||
| "sdmx-dimension": "http://purl.org/linked-data/sdmx/2009/dimension#", | |||
| "sdmx-measure": "http://purl.org/linked-data/sdmx/2009/measure#", | |||
| "xsd": "http://www.w3.org/2001/XMLSchema#", | |||
| "Datatype": "rdfs:Datatype", | |||
| "DatatypeProperty": "owl:DatatypeProperty", | |||
| "DimensionProperty": "qb:DimensionProperty", | |||
| "FunctionalProperty": "owl:FunctionalProperty", | |||
| "DimensionProperty": "qb:DimensionProperty", | |||
| "MeasureProperty": "owl:MeasureProperty", | |||
| "Ontology": "owl:Ontology", | |||
| "Property": "rdf:Property", | |||
| "defines": { | |||
| "@reverse": "rdfs:isDefinedBy" | |||
| }, | |||
| "comment": "rdfs:comment", | |||
| "concept": { | |||
| "@id": "qb:concept", | |||
| "@type": "@id" | |||
| }, | |||
| "created": { | |||
| "@id": "dct:created", | |||
| "@type": "xsd:date" | |||
| }, | |||
| "creator": { | |||
| "@id": "dct:creator", | |||
| "@type": "@id" | |||
| }, | |||
| "description": "dct:description", | |||
| "isDefinedBy": { | |||
| "@id": "rdfs:isDefinedBy", | |||
| "@type": "@id" | |||
| }, | |||
| "label": "rdfs:label", | |||
| "range": { | |||
| "@id": "rdfs:range", | |||
| "@type": "@id" | |||
| }, | |||
| "seeAlso": { | |||
| "@id": "rdfs:seeAlso", | |||
| "@type": "@id" | |||
| }, | |||
| "subPropertyOf": { | |||
| "@id": "rdfs:subPropertyOf", | |||
| "@type": "@id" | |||
| }, | |||
| "title": "dct:title" | |||
| }, | |||
| "@id": "prop:", | |||
| "@type": "Ontology", | |||
| "title": "Statistical ontology for on-line discussion spaces", | |||
| "created": "2020-03-06", | |||
| "creator": "https://wandystan.eu/B196", | |||
| "description": "This ontology defines properties used for publication of the statistical data about posts published in on-line discussion groups, lists and fora according to the RDF Data Cube model <https://www.w3.org/TR/vocab-data-cube/>.", | |||
| "defines": [ | |||
| { | |||
| "@id": "prop:date", | |||
| "@type": ["Property", "DatatypeProperty", "DimensionProperty", "FunctionalProperty"], | |||
| "label": "Date", | |||
| "comment": "Date in which posts were was sent.", | |||
| "concept": "sdmx-concept:refPeriod", | |||
| "range": "xsd:date", | |||
| "subPropertyOf": ["sdmx-dimension:refPeriod", "dct:date"] | |||
| }, { | |||
| "@id": "prop:name_fnv1a32sum", | |||
| "@type": ["Property", "DatatypeProperty"], | |||
| "label": "32-bit FNV-1a sum of a name", | |||
| "comment": "A name for some thing hashed with the 32-bit flavor of the FNV-1a algorithm.", | |||
| "range": "xsd:hexBinary" | |||
| }, { | |||
| "@id": "prop:period", | |||
| "@type": ["Property", "DimensionProperty", "ObjectProperty"], | |||
| "label": "Period", | |||
| "comment": "Period in which posts were sent.", | |||
| "concept": "sdmx-concept:refPeriod", | |||
| "range": "http://www.w3.org/2006/time#Interval", | |||
| "subPropertyOf": ["sdmx-dimension:refPeriod", "dct:date"] | |||
| }, { | |||
| "@id": "prop:posts", | |||
| "@type": ["Property", "DatatypeProperty", "FunctionalProperty", "MeasureProperty"], | |||
| "label": "Number of posts", | |||
| "comment": "Number of posts sent in a certain period of time.", | |||
| "concept": "sdmx-concept:obsValue", | |||
| "range": "xsd:nonNegativeInteger", | |||
| "subPropertyOf": "sdmx-measure:obsValue" | |||
| }, { | |||
| "@id": "prop:sender", | |||
| "@type": ["Property", "DimensionProperty", "FunctionalProperty", "ObjectProperty"], | |||
| "label": "Sender", | |||
| "comment": "Sender of the post (not necessarily a person, may be e.g. an automated posting agent).", | |||
| "range": "dct:Agent" | |||
| } | |||
| ] | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| <?php | |||
| require_once 'common.php'; | |||
| $hash = $_GET['hash']; | |||
| if (! mb_ereg_match('^[0-9a-f]{8}$', $hash)) | |||
| exit_error('Invalid hash.'); | |||
| header('Content-type: application/ld+json'); | |||
| print json_encode([ | |||
| '@context' => 'https://wandystan.eu/statistics/context.jsonld', | |||
| '@id' => 'sender/' . $hash, | |||
| '@type' => 'Agent', | |||
| 'name_fnv1a32sum' => $hash | |||
| ]); | |||
| @@ -0,0 +1,37 @@ | |||
| { | |||
| "@context": "https://wandystan.eu/statistics/context.jsonld", | |||
| "@graph": [ | |||
| { | |||
| "@id": "structure/by-period", | |||
| "@type": "DataStructureDefinition", | |||
| "component": [ | |||
| { | |||
| "measure": "prop:posts" | |||
| }, { | |||
| "dimension": "prop:sender", | |||
| "order": 1 | |||
| }, { | |||
| "dimension": "prop:date", | |||
| "order": 2 | |||
| }, { | |||
| "componentAttachment": "Slice", | |||
| "dimension": "prop:period", | |||
| "order": 3 | |||
| } | |||
| ], | |||
| "sliceKey": "key/by-period" | |||
| }, { | |||
| "@id": "key/by-period", | |||
| "@type": "SliceKey", | |||
| "label": { | |||
| "en": "time slice", | |||
| "pl": "wycinek czasu" | |||
| }, | |||
| "comment": { | |||
| "en": "Slice grouping data from a given time period.", | |||
| "pl": "Wycinek grupujący dane z danego okresu czasowego." | |||
| }, | |||
| "componentProperty": "prop:period" | |||
| } | |||
| ] | |||
| } | |||