In bash you can set a variable to ‚readonly‘. This can be very useful to prevent accidental overwrites.
readonly INSTALLDIR="/opt/goodSoftware"
In bash you can set a variable to ‚readonly‘. This can be very useful to prevent accidental overwrites.
readonly INSTALLDIR="/opt/goodSoftware"
Im folgenden teile ich hier einige Gedanken zu dem Papier:
„Harmonisiertes Metadatenschema für die DSpace-Repositorien der Berliner Universitäten – Ergebnis der Arbeitsgruppe DSpace Metadaten bestehend aus Mitgliedern der Charité – Universitätsmedizin Berlin, der Freien Universität Berlin, der Humboldt-Universität zu Berlin und der Technischen Universität Berlin“
Zu finden hier: https://refubium.fu-berlin.de/handle/fub188/37260
Direktlink zum Datensatz hier: https://refubium.fu-berlin.de/bitstream/handle/fub188/37260/Berlin_DSpace_MDS.xlsx?sequence=1&isAllowed=y&save=y
Als Entwickler finde ich die im Abstract formulierten Zielsetzungen besonders wichtig und erfreulich:
„Ziel ist, innerhalb der Berliner Universitäten einen einheitlichen
Gebrauch der Metadaten zu gewährleisten. Gleichzeitig wird es bei
Einführung des neuen Modells möglich sein, Mappingtabellen, Schnittstellen
und Programmierarbeiten zwischen den beteiligten Einrichtungen leichter
auszutauschen.“
Trigger
Das Arbeitsergebnis wurde als Excel-Datei veröffentlicht. Dies reicht als Grundlage für einen gelungenen Datenaustausch natürlich noch nicht aus. Typische Folgefragen von Softwareentwicklern sind:
– Wo finde ich die konkreten Schemadateien?
– Gibt es Testsysteme?
– Welche Protokolle/APIs sollen zum Austausch der Daten angeboten und genutzt werden?
– Wie sieht es mit Mehrsprachigkeit in den Metadaten aus?
Aber zurück zum vorliegenden Datensatz:
Beobachtung
An vielen Stellen in der Excel-Datei steht als Datentyp Freitext. Es gibt kaum MetaMetadaten. An einigen Stellen erscheint das Modell zu flach und zu spezifisch. Dies ist in gewisser Weise Schade, da hier die zitierte. Zielsetzung möglicherweise durch „ein paar Handgriffe“ optimaler unterstützt werden könnte.
Beispiel aus Zeile 22-24:
| Feld | Beispielwert |
| dc.subject | open access |
| dc.subject.ddc | 300 Sozialwissenschaften |
| dc.subject.rvk | AK 54355 |
Ein paar Dinge fallen hier auf:
1. In den Freitextfeldern werden Notationen und Label gemischt
2. Für einzelne Notationssyteme existieren spezielle Unterfelder (ddc,rvk). Dies ist nicht gut erweiterbar. Besser wäre es zu jedem Subject das Notationssystem zu vermerken und für diesen Vermerk seinerseits ein kontrolliertes Vokabular (z.B. basierend auf Wikidata, s.u.) zu definieren.
3. Es wird nicht ganz klar, wie Mehrsprachigkeit realisiert werden soll.
4. Es gibt kein (Sub)Feld indem z.B. URIs auf SKOS-Vokabulare mitgeführt werden könnten.
These
Um den Bereich „subject“ besser maschinell nachnutzbar zu machen, sollten kontrollierte SKOS-Vokabulare die Regel sein. Wenn möglich sollten URIs zur Identifikation von verwendeten Termen mit im Datensatz gespeichert werden.
In jedem Fall sollten Notationen, Label und IDs im Datenmodell in getrennte Unterfelder laufen. Labels sollten mehrsprachig im Datensatz mitgeführt werden können bzw. über eine URI leicht nachgeladen werden können.
Beispiel und Vorschlag
Das Beispiel zeigt ein Schlagwort im Feld subject mit zusätzlichen Informationen.
"subject":[{
"id":"http://dewey.info/class/300",
"notation":"300",
"prefLabel": "Sozialwissenschaften",
"label":{
"de":"Sozialwissenschaften"
"en": "Social Sciences"
"fr":"...."
},
"source":{
"id":"https://www.wikidata.org/wiki/Q15222117",
"label":{
"en": "Dewey Decimal Classification"
}
"similarTo": "https://www.wikidata.org/wiki/Q34749"
}
}]
Zusätzlich zu dem Schlagwort werden Informationen zur Quelle und zum Notationssystem gegeben. Notation und Schlagwort werden getrennt. Es wird über einen Link auf Wikidata eine Verlinkung in andere Schlagwortsysteme realisiert.
Und was bringt das?
Dies hat vor allem Vorteile auf der maschinellen Konsumentenseite.
Blogpost for this stackoverflow answer: https://stackoverflow.com/a/74701083/1485527
Get code here
Create example app
npx create-react-app read-env-example --template typescript
Navigate to fresh app
cd read-env-example
Create Dockerfile
mkdir -p docker/build
docker/build/Dockerfile
# build environment
FROM node:19-alpine3.15 as builder
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY package-lock.json ./
RUN npm ci
RUN npm install react-scripts@5.0.1 -g
COPY . ./
RUN PUBLIC_URL="." npm run build
# production environment
FROM nginx:stable-alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
COPY docker/build/docker-entrypoint.sh /
RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]
Create docker-entrypoint.sh
This script will be executed at container start.
It generates the config.js file containing all environment variables starting with ‚MYAPP‘ under window.extended.
docker/build/docker-entrypoint.sh
#!/bin/sh -eu
function generateConfigJs(){
echo "/*<![CDATA[*/";
echo "window.extended = window.extended || {};";
for i in `env | grep '^MYAPP'`
do
key=$(echo "$i" | cut -d"=" -f1);
val=$(echo "$i" | cut -d"=" -f2);
echo "window.extended.${key}='${val}' ;";
done
echo "/*]]>*/";
}
generateConfigJs > /usr/share/nginx/html/config.js
nginx -g "daemon off;"
Create docker-compose.yml
mkdir docker/run
docker/run/docker-compose.yml
version: "3.2"
services:
read-env-example:
image: read-env-example:0.1.0
ports:
- 80:80
env_file:
- myapp.env
Create runtime config for your app
docker/run/myapp.env
MYAPP_API_ENDPOINT='http://elasticsearch:9200'
Create config.js <– this is where .env will be injected.
public/config.js
/*<![CDATA[*/
window.extended = window.extended || {};
window.extended.MYAPP_API_ENDPOINT='http://localhost:9200';
/*]]>*/
Note: This file will be completely overwritten by the docker-entrypoint.sh. For development purposes you can set it to any value that is appropriate, e.g. when used together with npm start.
Include config.js in index.html
public/index.html
<head>
...
<script type="text/javascript" src="%PUBLIC_URL%/config.js" ></script>
...
</head>
<body>
Make use of your environment variable
src/App.tsx
declare global {
interface Window { extended: any; }
}
function App() {
return (
<div className="App">
<header className="App-header">
You have configured {window.extended.MYAPP_API_ENDPOINT}
</header>
</div>
);
}
Build
npm install
Create docker image
docker build -f docker/build/Dockerfile -t read-env-example:0.1.0 .
Run container
docker-compose -f ./docker/run/docker-compose.yml up
Navigate to your app
Open http://localhost in your browser.
You will see the content of MYAPP_API_ENDPOINT like provided in your docker/run/myapp.env.
Further usage
You can provide additional variables starting with MYAPP. The docker-entrypoint.sh script will search for all variables starting with MYAPP and make them available through the windows object.
For most people, the word “integration” creates the impression of connecting systems together, of sharing data to keep systems in sync. I believe that definition of integration is insufficient to meet the demands of a modern digital business, and that the real goal of integration done well is to create clean interfaces between capabilities.
At the example of this stackoverflow question:
„Supposing we have the following triple in Turtle syntax:
<http:/example.com/Paul> <http:/example.com/running> <http:/example.com/10miles> .
How do I add a start and end time? For example if I want to say he started at 10 am and finished his 10miles run at 12 am. I want to use xsd:dateTime.“
Sometimes it can be hard to create good, well fitting models. In my own experience it is crucial to identify a well defined set of entities and relations to create a vocabulary from. Some people prefer to use visual strategies to develop their models. I prefer to write models in structured text. This has the advantage that the process of modeling directly leads into actual coding.
Here is an example on how I would tackle the question .
1. The modelling part (not much RDF involved)
{
"runs": [
{
"id": "runs:0000001",
"distance": {
"length": 10.0,
"unit": "mile"
},
"time": {
"start": "2018-04-09T10:00:00",
"end": "2018-04-09T12:00:00"
},
"runner": {
"id": "runner:0000002",
"name": "Paul"
}
}
]
}
We store the json document in a file run.json. From here we can use the ‚oi‘ command line tool , to create an adhoc context.
oi run.json -t context
The resulting context is just a stub. But with a few additions we can easily create a context document to define id’s and types for each vocable/entity/relation.
2. The RDF part: define a proper context for your document.
{
"@context": {
"ical": "http://www.w3.org/2002/12/cal/ical#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"runs": {
"@id": "info:stack/49726990/runs/",
"@container": "@list"
},
"distance": {
"@id": "info:stack/49726990/distance"
},
"length": {
"@id": "info:stack/49726990/length",
"@type": "xsd:double"
},
"unit": {
"@id": "info:stack/49726990/unit"
},
"runner": {
"@id": "info:stack/49726990/runner/"
},
"name": {
"@id": "info:stack/49726990/name"
},
"time": {
"@id": "info:stack/49726990/time"
},
"start": {
"@id":"ical:dtstart",
"@type": "xsd:dateTime"
},
"end": {
"@id":"ical:dtend",
"@type": "xsd:dateTime"
},
"id": "@id"
}
}
3. The fun part: Throw it to an RDF converter of your choice
This is how it looks in JSON-Playground
Or simply use ‚oi‘:
oi run.json -f run.context -t ntriples
Prints:
_:b0 <info:stack/49726990/runs/> _:b3 .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <info:stack/49726990/runs/0000001> .
_:b3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
<info:stack/49726990/runs/0000001> <info:stack/49726990/distance> _:b1 .
<info:stack/49726990/runs/0000001> <info:stack/49726990/runner/> <info:stack/49726990/runner/0000002> .
<info:stack/49726990/runs/0000001> <info:stack/49726990/time> _:b2 .
_:b1 <info:stack/49726990/length> "1.0E1"^^<http://www.w3.org/2001/XMLSchema#double> .
_:b1 <info:stack/49726990/unit> "mile" .
<info:stack/49726990/runner/0000002> <info:stack/49726990/name> "Paul" .
_:b2 <http://www.w3.org/2002/12/cal/ical#dtend> "2018-04-09T12:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
_:b2 <http://www.w3.org/2002/12/cal/ical#dtstart> "2018-04-09T10:00:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
https://github.com/jschnasse/oi
wget https://dl.bintray.com/jschnasse/debian/oi_0.5.10.deb
sudo apt install ./oi_0.5.10.deb