##############################################################################
# membership SHACL shapes  —  v1.1.0
#
# Validation lives here, not in OWL domains/ranges. Validate a data graph that
# is merged with the ontology and codelists, so sh:class sees the subclass
# hierarchy (e.g. mbr:Office ⊑ org:Role ⊑ skos:Concept).
#
# Also merge the mappings (mappings/generated/*.ttl) when your data uses concepts
# from your own codelists: a value taken from a codelist is checked against the
# hub scheme for its property (see "Codelist values"), and a local concept passes
# only if a mapping places it in that scheme.
#
# Dates may be partial (xsd:date, xsd:gYearMonth, xsd:gYear). An end is reported as
# before its start only when it is certainly so: the latest moment the end could
# mean lies before the earliest moment the start could mean. Supported: years
# 0001-9999 written with four digits. A timezone on a date is ignored, so the
# calendar date as written is compared. A date outside that form is not ordered;
# it gives a warning instead of passing silently.
##############################################################################

@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl:     <http://www.w3.org/2002/07/owl#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix sh:      <http://www.w3.org/ns/shacl#> .
@prefix skos:    <http://www.w3.org/2004/02/skos/core#> .
@prefix foaf:    <http://xmlns.com/foaf/0.1/> .
@prefix schema:  <http://schema.org/> .
@prefix org:     <http://www.w3.org/ns/org#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix rov:     <http://www.w3.org/ns/regorg#> .
@prefix adms:    <http://www.w3.org/ns/adms#> .
@prefix mbr:    <https://w3id.org/membership#> .
@prefix mbrc:   <https://w3id.org/membership/code/> .
@prefix mbrsh:<https://w3id.org/membership/shapes#> .

<https://w3id.org/membership/shapes>
    a owl:Ontology ;
    owl:versionInfo "1.1.0" ;
    rdfs:label "membership SHACL shapes"@en , "SHACL-regler för membership"@sv , "SHACL-Shapes für membership"@de , "Shapes SHACL pour membership"@fr , "Shape SHACL per membership"@it , "Formas SHACL de membership"@es , "Formas SHACL de membership (regras de validação)"@pt , "A membership SHACL-szabályai"@hu , "Κανόνες SHACL για το membership"@el , "SHACL-regels voor membership"@nl ;
    dcterms:license <https://creativecommons.org/licenses/by/4.0/> ;
    dcterms:creator <https://orcid.org/0009-0002-6239-5346> ;
    dcterms:rightsHolder <https://orcid.org/0009-0002-6239-5346> ;
    dcterms:publisher <https://github.com/society-ontologies> ;
    sh:declare [ sh:prefix "mbr" ; sh:namespace "https://w3id.org/membership#"^^xsd:anyURI ] ,
               [ sh:prefix "mbrc" ; sh:namespace "https://w3id.org/membership/code/"^^xsd:anyURI ] ,
               [ sh:prefix "org" ; sh:namespace "http://www.w3.org/ns/org#"^^xsd:anyURI ] ,
               [ sh:prefix "xsd" ; sh:namespace "http://www.w3.org/2001/XMLSchema#"^^xsd:anyURI ] ,
               [ sh:prefix "schema" ; sh:namespace "http://schema.org/"^^xsd:anyURI ] .

<https://orcid.org/0009-0002-6239-5346> foaf:name "Oscar Almgren" .

<https://github.com/society-ontologies> a foaf:Organization ;
    foaf:name "Society Ontologies" .

##############################################################################
# Dates: xsd:date, xsd:gYearMonth or xsd:gYear; at most one of each
##############################################################################

mbrsh:DateList
    sh:or ( [ sh:datatype xsd:date ] [ sh:datatype xsd:gYearMonth ] [ sh:datatype xsd:gYear ] ) .

mbrsh:StartDateShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:startDate ;
    sh:property [
        sh:path mbr:startDate ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:startDate must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:startDate ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:startDate doit être un unique xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:startDate muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:startDate deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:startDate debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:startDate tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:startDate értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:startDate πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:startDate moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] .

mbrsh:EndDateShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:endDate ;
    sh:property [
        sh:path mbr:endDate ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:endDate must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:endDate ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:endDate doit être un unique xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:endDate muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:endDate deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:endDate debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:endDate tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:endDate értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:endDate πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:endDate moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] ;
    # An end cannot come before its start. Partial dates are widened to the earliest
    # and latest day they could mean ("2000" is 2000-01-01 to 2000-12-31, "2000-03" is
    # 2000-03-01 to 2000-03-31; 31 is an upper bound, not a calendar day), and the
    # ISO form makes the text order the date order. Only an end whose latest day is
    # before the start's earliest day is an error.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "The end date is certainly before the start date. | Slutdatumet ligger säkert före startdatumet. | La date de fin est certainement antérieure à la date de début. | Das Enddatum liegt sicher vor dem Startdatum. | La data di fine è certamente anteriore alla data di inizio. | La fecha de fin es con seguridad anterior a la fecha de inicio. | A data de fim é com certeza anterior à data de início. | A záró dátum biztosan korábbi a kezdő dátumnál. | Η ημερομηνία λήξης είναι σίγουρα πριν από την ημερομηνία έναρξης. | De einddatum ligt zeker vóór de begindatum." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this WHERE {
                $this mbr:startDate ?s ;
                      mbr:endDate ?e .
                FILTER (datatype(?s) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                        datatype(?e) IN (xsd:date, xsd:gYearMonth, xsd:gYear))
                FILTER (REGEX(STR(?s), "^[0-9]{4}") && REGEX(STR(?e), "^[0-9]{4}"))
                BIND (IF(datatype(?s) = xsd:date, SUBSTR(STR(?s), 1, 10),
                      IF(datatype(?s) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?s), 1, 7), "-01"),
                         CONCAT(SUBSTR(STR(?s), 1, 4), "-01-01"))) AS ?earliestStart)
                BIND (IF(datatype(?e) = xsd:date, SUBSTR(STR(?e), 1, 10),
                      IF(datatype(?e) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?e), 1, 7), "-31"),
                         CONCAT(SUBSTR(STR(?e), 1, 4), "-12-31"))) AS ?latestEnd)
                FILTER (?latestEnd < ?earliestStart)
            }
        """
    ] .

# Dates that the ordering checks cannot compare are reported, not passed over.
mbrsh:SupportedDateFormShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:startDate , mbr:endDate , mbr:foundingDate , mbr:dissolutionDate , mbr:decisionDate ;
    sh:severity sh:Warning ;
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "The date {?value} is not a year 0001-9999 written with four digits, so its order against other dates is not checked. | Datumet {?value} är inte ett år 0001-9999 skrivet med fyra siffror, så dess ordning mot andra datum kontrolleras inte. | La date {?value} n'est pas une année de 0001 à 9999 écrite avec quatre chiffres ; son ordre par rapport aux autres dates n'est donc pas vérifié. | Das Datum {?value} ist kein vierstellig geschriebenes Jahr von 0001 bis 9999, daher wird seine Reihenfolge gegenüber anderen Daten nicht geprüft. | La data {?value} non è un anno da 0001 a 9999 scritto con quattro cifre, quindi il suo ordine rispetto alle altre date non viene controllato. | La fecha {?value} no es un año 0001-9999 escrito con cuatro cifras, por lo que no se comprueba su orden respecto a otras fechas. | A data {?value} não é um ano 0001-9999 escrito com quatro algarismos, pelo que não se verifica a sua ordem em relação a outras datas. | A(z) {?value} dátum nem négy számjeggyel írt 0001–9999 év, ezért más dátumokhoz viszonyított sorrendjét nem ellenőrizzük. | Η ημερομηνία {?value} δεν είναι έτος 0001–9999 γραμμένο με τέσσερα ψηφία, οπότε η σειρά της σε σχέση με άλλες ημερομηνίες δεν ελέγχεται. | De datum {?value} is geen jaar 0001-9999 met vier cijfers geschreven, dus de volgorde ten opzichte van andere datums wordt niet gecontroleerd." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?value WHERE {
                $this mbr:startDate|mbr:endDate|mbr:foundingDate|mbr:dissolutionDate|mbr:decisionDate ?value .
                FILTER (datatype(?value) IN (xsd:date, xsd:gYearMonth, xsd:gYear))
                FILTER (!REGEX(STR(?value), "^[0-9]{4}(-[0-9]{2}(-[0-9]{2})?)?(Z|[+-][0-9]{2}:[0-9]{2})?$"))
            }
        """
    ] .

##############################################################################
# Codelist values
#
# A value of a codelist property must be a concept in the hub scheme for that
# property, or a local concept that is mapped to a concept in that scheme with
# skos:exactMatch, skos:closeMatch or skos:broadMatch (it is narrower than, or
# the same as, a hub concept). The three are not interchangeable and none is
# owl:sameAs. A local concept that is only related to the hub (skos:relatedMatch),
# or broader than a hub concept (skos:narrowMatch), is not accepted. A mapping does not make an organisation a mbr:GentlemensClub
# or other convenience class: those are defined by owl:hasValue on the hub
# concept itself.
##############################################################################

mbrsh:OrganizationTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:OrganizationTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:OrganizationTypes ] ) .

mbrsh:MembershipStatusValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:MembershipStatuses ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:MembershipStatuses ] ) .

mbrsh:MembershipCategoryValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:MembershipCategories ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:MembershipCategories ] ) .

mbrsh:MembershipEventTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:MembershipEventTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:MembershipEventTypes ] ) .

mbrsh:GatheringTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:GatheringTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:GatheringTypes ] ) .

mbrsh:ParticipationRoleValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:ParticipationRoles ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:ParticipationRoles ] ) .

mbrsh:DressCodeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:DressCodes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:DressCodes ] ) .

mbrsh:GenderPolicyValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:GenderPolicies ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:GenderPolicies ] ) .

mbrsh:AdmissionModeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:AdmissionModes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:AdmissionModes ] ) .

mbrsh:DistinctionTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:DistinctionTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:DistinctionTypes ] ) .

mbrsh:MaterialValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:Materials ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:Materials ] ) .

mbrsh:OrganizationStatusValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:OrganizationStatuses ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:OrganizationStatuses ] ) .

mbrsh:OwnershipModelValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:OwnershipModels ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:OwnershipModels ] ) .

mbrsh:FeeTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:FeeTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:FeeTypes ] ) .

mbrsh:OfficeTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:OfficeTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:OfficeTypes ]
            [ sh:path ( skos:inScheme dcterms:isPartOf ) ; sh:hasValue mbrc:OfficeTypes ] ) .

mbrsh:LegalFormValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:LegalForms ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:LegalForms ] ) .

mbrsh:ApplicationStatusValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:ApplicationStatuses ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:ApplicationStatuses ] ) .

mbrsh:CharterStatusValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:CharterStatuses ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:CharterStatuses ] ) .

mbrsh:ChangeEventTypeValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:ChangeEventTypes ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:ChangeEventTypes ] ) .

mbrsh:PublicBenefitStatusValue a sh:NodeShape ;
    sh:or ( [ sh:path skos:inScheme ; sh:hasValue mbrc:PublicBenefitStatuses ]
            [ sh:path ( [ sh:alternativePath ( skos:exactMatch skos:closeMatch skos:broadMatch ) ] skos:inScheme ) ; sh:hasValue mbrc:PublicBenefitStatuses ]
            [ sh:path ( skos:inScheme dcterms:isPartOf ) ; sh:hasValue mbrc:PublicBenefitStatuses ] ) .

mbrsh:FoundingDateShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:foundingDate ;
    sh:property [
        sh:path mbr:foundingDate ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:foundingDate must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:foundingDate ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:foundingDate doit être un unique xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:foundingDate muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:foundingDate deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:foundingDate debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:foundingDate tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:foundingDate értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:foundingDate πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:foundingDate moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] .

mbrsh:DissolutionDateShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:dissolutionDate ;
    sh:property [
        sh:path mbr:dissolutionDate ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:dissolutionDate must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:dissolutionDate ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:dissolutionDate doit être un unique xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:dissolutionDate muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:dissolutionDate deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:dissolutionDate debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:dissolutionDate tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:dissolutionDate értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:dissolutionDate πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:dissolutionDate moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] .

# A decision may come before or after it takes effect, so it is not ordered against mbr:startDate.
mbrsh:DecisionDateShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:decisionDate ;
    sh:property [
        sh:path mbr:decisionDate ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:decisionDate must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:decisionDate ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:decisionDate doit être un seul xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:decisionDate muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:decisionDate deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:decisionDate debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:decisionDate tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:decisionDate értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:decisionDate πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:decisionDate moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] .

mbrsh:AsOfShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:asOf ;
    sh:property [
        sh:path mbr:asOf ;
        sh:maxCount 1 ;
        sh:node mbrsh:DateList ;
        sh:message "mbr:asOf must be a single xsd:date, xsd:gYearMonth or xsd:gYear. | mbr:asOf ska vara ett enda xsd:date, xsd:gYearMonth eller xsd:gYear. | mbr:asOf doit être un unique xsd:date, xsd:gYearMonth ou xsd:gYear. | mbr:asOf muss ein einzelnes xsd:date, xsd:gYearMonth oder xsd:gYear sein. | mbr:asOf deve essere un unico xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:asOf debe ser un único xsd:date, xsd:gYearMonth o xsd:gYear. | mbr:asOf tem de ser um único xsd:date, xsd:gYearMonth ou xsd:gYear. | Az mbr:asOf értéke egyetlen xsd:date, xsd:gYearMonth vagy xsd:gYear kell legyen. | Το mbr:asOf πρέπει να είναι ένα μόνο xsd:date, xsd:gYearMonth ή xsd:gYear. | mbr:asOf moet één xsd:date, xsd:gYearMonth of xsd:gYear zijn."
    ] .

##############################################################################
# Membership
##############################################################################

mbrsh:MembershipShape a sh:NodeShape ;
    sh:targetClass mbr:Membership ;
    sh:property [ sh:path org:member ; sh:minCount 1 ; sh:maxCount 1 ; sh:class foaf:Agent ] ,
                [ sh:path org:organization ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ] ,
                [ sh:path mbr:membershipStatus ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipStatusValue ;
                  sh:message "mbr:membershipStatus must be a concept in mbrc:MembershipStatuses, or one mapped to it. | mbr:membershipStatus ska vara ett begrepp i mbrc:MembershipStatuses, eller ett som är mappat dit. | mbr:membershipStatus doit être un concept de mbrc:MembershipStatuses, ou un concept qui y est mappé. | mbr:membershipStatus muss ein Konzept aus mbrc:MembershipStatuses sein oder eines, das darauf abgebildet ist. | mbr:membershipStatus deve essere un concetto di mbrc:MembershipStatuses, o uno associato a esso. | mbr:membershipStatus debe ser un concepto de mbrc:MembershipStatuses, o uno asociado a él. | mbr:membershipStatus tem de ser um conceito de mbrc:MembershipStatuses, ou um associado a ele. | Az mbr:membershipStatus értéke az mbrc:MembershipStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:membershipStatus πρέπει να είναι έννοια του mbrc:MembershipStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:membershipStatus moet een concept in mbrc:MembershipStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                # A membership may have several categories at once (life and founding, junior
                # and overseas): no maxCount, and no incompatibility rule beyond what a
                # category's own definition says.
                [ sh:path mbr:membershipCategory ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipCategoryValue ;
                  sh:message "mbr:membershipCategory must be a concept in mbrc:MembershipCategories, or one mapped to it. | mbr:membershipCategory ska vara ett begrepp i mbrc:MembershipCategories, eller ett som är mappat dit. | mbr:membershipCategory doit être un concept de mbrc:MembershipCategories, ou un concept qui y est mappé. | mbr:membershipCategory muss ein Konzept aus mbrc:MembershipCategories sein oder eines, das darauf abgebildet ist. | mbr:membershipCategory deve essere un concetto di mbrc:MembershipCategories, o uno associato a esso. | mbr:membershipCategory debe ser un concepto de mbrc:MembershipCategories, o uno asociado a él. | mbr:membershipCategory tem de ser um conceito de mbrc:MembershipCategories, ou um associado a ele. | Az mbr:membershipCategory értéke az mbrc:MembershipCategories egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:membershipCategory πρέπει να είναι έννοια του mbrc:MembershipCategories, ή αντιστοιχισμένη σε αυτό. | mbr:membershipCategory moet een concept in mbrc:MembershipCategories zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:sponsor ; sh:class foaf:Agent ] ,
                [ sh:path mbr:proposer ; sh:class foaf:Agent ] ,
                [ sh:path mbr:seconder ; sh:class foaf:Agent ] ,
                [ sh:path mbr:mentor ; sh:class foaf:Agent ] ,
                [ sh:path mbr:membershipNumber ; sh:maxCount 1 ; sh:datatype xsd:string ;
                  sh:message "mbr:membershipNumber must be one xsd:string, such as \"1207\" or \"L-0042\". | mbr:membershipNumber ska vara en enda xsd:string, t.ex. \"1207\" eller \"L-0042\". | mbr:membershipNumber doit être un seul xsd:string, comme \"1207\" ou \"L-0042\". | mbr:membershipNumber muss ein einzelner xsd:string sein, etwa \"1207\" oder \"L-0042\". | mbr:membershipNumber deve essere un unico xsd:string, come \"1207\" o \"L-0042\". | mbr:membershipNumber debe ser un único xsd:string, como \"1207\" o \"L-0042\". | mbr:membershipNumber tem de ser um único xsd:string, como \"1207\" ou \"L-0042\". | Az mbr:membershipNumber értéke egyetlen xsd:string kell legyen, például \"1207\" vagy \"L-0042\". | Το mbr:membershipNumber πρέπει να είναι ένα μόνο xsd:string, όπως \"1207\" ή \"L-0042\". | mbr:membershipNumber moet één xsd:string zijn, zoals \"1207\" of \"L-0042\"." ] ;
    # Register policy: a number identifies one membership in one organisation at a time.
    # The same number may be reused by a later membership, but only when the two periods
    # certainly do not overlap: one ends (latest possible day) before the other begins
    # (earliest possible day), compared as in mbrsh:EndDateShape. A membership without
    # dates cannot show that, so a shared number is reported.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "Membership number {?num} is used by more than one membership in {?org} at overlapping or unknown times. | Medlemsnummer {?num} används av mer än ett medlemskap i {?org} under överlappande eller okända tider. | Le numéro d'adhérent {?num} est utilisé par plus d'une adhésion dans {?org} à des moments qui se chevauchent ou qui sont inconnus. | Die Mitgliedsnummer {?num} wird in {?org} von mehr als einer Mitgliedschaft zu sich überschneidenden oder unbekannten Zeiten verwendet. | Il numero di socio {?num} è usato da più di un'appartenenza in {?org} in periodi che si sovrappongono o non sono noti. | El número de socio {?num} lo usa más de una pertenencia en {?org} en períodos que se solapan o se desconocen. | O número de sócio {?num} é usado por mais de uma filiação em {?org} em períodos que se sobrepõem ou são desconhecidos. | A(z) {?num} tagsági számot egynél több tagság használja a(z) {?org} szervezetben egymást átfedő vagy ismeretlen időszakokban. | Ο αριθμός μέλους {?num} χρησιμοποιείται από περισσότερες από μία ιδιότητες μέλους στην {?org} σε περιόδους που επικαλύπτονται ή είναι άγνωστες. | Lidnummer {?num} wordt door meer dan één lidmaatschap in {?org} gebruikt op elkaar overlappende of onbekende tijden." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?num ?org WHERE {
                $this mbr:membershipNumber ?num ;
                      org:organization ?org .
                ?other mbr:membershipNumber ?num ;
                       org:organization ?org .
                FILTER (?other != $this)
                FILTER NOT EXISTS {
                    $this mbr:endDate ?e .
                    ?other mbr:startDate ?s .
                    FILTER (datatype(?e) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                            datatype(?s) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                            REGEX(STR(?e), "^[0-9]{4}") && REGEX(STR(?s), "^[0-9]{4}"))
                    BIND (IF(datatype(?e) = xsd:date, SUBSTR(STR(?e), 1, 10),
                          IF(datatype(?e) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?e), 1, 7), "-31"),
                             CONCAT(SUBSTR(STR(?e), 1, 4), "-12-31"))) AS ?latestEnd)
                    BIND (IF(datatype(?s) = xsd:date, SUBSTR(STR(?s), 1, 10),
                          IF(datatype(?s) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?s), 1, 7), "-01"),
                             CONCAT(SUBSTR(STR(?s), 1, 4), "-01-01"))) AS ?earliestStart)
                    FILTER (?latestEnd < ?earliestStart)
                }
                FILTER NOT EXISTS {
                    ?other mbr:endDate ?e .
                    $this mbr:startDate ?s .
                    FILTER (datatype(?e) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                            datatype(?s) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                            REGEX(STR(?e), "^[0-9]{4}") && REGEX(STR(?s), "^[0-9]{4}"))
                    BIND (IF(datatype(?e) = xsd:date, SUBSTR(STR(?e), 1, 10),
                          IF(datatype(?e) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?e), 1, 7), "-31"),
                             CONCAT(SUBSTR(STR(?e), 1, 4), "-12-31"))) AS ?latestEnd)
                    BIND (IF(datatype(?s) = xsd:date, SUBSTR(STR(?s), 1, 10),
                          IF(datatype(?s) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?s), 1, 7), "-01"),
                             CONCAT(SUBSTR(STR(?s), 1, 4), "-01-01"))) AS ?earliestStart)
                    FILTER (?latestEnd < ?earliestStart)
                }
            }
        """
    ] ,
    # A member is not their own mentor.
    [
        a sh:SPARQLConstraint ;
        sh:message "A member cannot be their own mentor (mbr:mentor). | En medlem kan inte vara sin egen fadder (mbr:mentor). | Un membre ne peut pas être son propre mentor (mbr:mentor). | Ein Mitglied kann nicht sein eigener Mentor sein (mbr:mentor). | Un socio non può essere il proprio mentore (mbr:mentor). | Un miembro no puede ser su propio mentor (mbr:mentor). | Um membro não pode ser o seu próprio mentor (mbr:mentor). | Egy tag nem lehet a saját mentora (mbr:mentor). | Ένα μέλος δεν μπορεί να είναι ο μέντορας του εαυτού του (mbr:mentor). | Een lid kan niet zijn of haar eigen mentor zijn (mbr:mentor)." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?m WHERE {
                $this mbr:mentor ?m ;
                      org:member ?m .
            }
        """
    ] .

mbrsh:MembershipEventShape a sh:NodeShape ;
    sh:targetClass mbr:MembershipEvent ;
    sh:property [ sh:path mbr:concernsMembership ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Membership ] ,
                [ sh:path mbr:membershipEventType ; sh:minCount 1 ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipEventTypeValue ;
                  sh:message "mbr:membershipEventType must be a concept in mbrc:MembershipEventTypes, or one mapped to it. | mbr:membershipEventType ska vara ett begrepp i mbrc:MembershipEventTypes, eller ett som är mappat dit. | mbr:membershipEventType doit être un concept de mbrc:MembershipEventTypes, ou un concept qui y est mappé. | mbr:membershipEventType muss ein Konzept aus mbrc:MembershipEventTypes sein oder eines, das darauf abgebildet ist. | mbr:membershipEventType deve essere un concetto di mbrc:MembershipEventTypes, o uno associato a esso. | mbr:membershipEventType debe ser un concepto de mbrc:MembershipEventTypes, o uno asociado a él. | mbr:membershipEventType tem de ser um conceito de mbrc:MembershipEventTypes, ou um associado a ele. | Az mbr:membershipEventType értéke az mbrc:MembershipEventTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:membershipEventType πρέπει να είναι έννοια του mbrc:MembershipEventTypes, ή αντιστοιχισμένη σε αυτό. | mbr:membershipEventType moet een concept in mbrc:MembershipEventTypes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:resultingStatus ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipStatusValue ;
                  sh:message "mbr:resultingStatus must be a concept in mbrc:MembershipStatuses, or one mapped to it. | mbr:resultingStatus ska vara ett begrepp i mbrc:MembershipStatuses, eller ett som är mappat dit. | mbr:resultingStatus doit être un concept de mbrc:MembershipStatuses, ou un concept qui y est mappé. | mbr:resultingStatus muss ein Konzept aus mbrc:MembershipStatuses sein oder eines, das darauf abgebildet ist. | mbr:resultingStatus deve essere un concetto di mbrc:MembershipStatuses, o uno associato a esso. | mbr:resultingStatus debe ser un concepto de mbrc:MembershipStatuses, o uno asociado a él. | mbr:resultingStatus tem de ser um conceito de mbrc:MembershipStatuses, ou um associado a ele. | Az mbr:resultingStatus értéke az mbrc:MembershipStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:resultingStatus πρέπει να είναι έννοια του mbrc:MembershipStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:resultingStatus moet een concept in mbrc:MembershipStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                # The whole set of categories after the event, not an addition to the earlier set.
                [ sh:path mbr:resultingCategory ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipCategoryValue ;
                  sh:message "mbr:resultingCategory must be a concept in mbrc:MembershipCategories, or one mapped to it. | mbr:resultingCategory ska vara ett begrepp i mbrc:MembershipCategories, eller ett som är mappat dit. | mbr:resultingCategory doit être un concept de mbrc:MembershipCategories, ou un concept qui y est mappé. | mbr:resultingCategory muss ein Konzept aus mbrc:MembershipCategories sein oder eines, das darauf abgebildet ist. | mbr:resultingCategory deve essere un concetto di mbrc:MembershipCategories, o uno associato a esso. | mbr:resultingCategory debe ser un concepto de mbrc:MembershipCategories, o uno asociado a él. | mbr:resultingCategory tem de ser um conceito de mbrc:MembershipCategories, ou um associado a ele. | Az mbr:resultingCategory értéke az mbrc:MembershipCategories egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:resultingCategory πρέπει να είναι έννοια του mbrc:MembershipCategories, ή αντιστοιχισμένη σε αυτό. | mbr:resultingCategory moet een concept in mbrc:MembershipCategories zijn, of een concept dat daarop is afgebeeld." ] .

##############################################################################
# Membership applications and ballots
##############################################################################

mbrsh:MembershipApplicationShape a sh:NodeShape ;
    sh:targetClass mbr:MembershipApplication ;
    sh:property [ sh:path mbr:applicant ; sh:minCount 1 ; sh:maxCount 1 ; sh:class foaf:Agent ;
                  sh:message "A membership application needs exactly one applicant (mbr:applicant). | En medlemsansökan behöver exakt en sökande (mbr:applicant). | Une demande d'adhésion a besoin d'exactement un candidat (mbr:applicant). | Ein Mitgliedschaftsantrag braucht genau einen Antragsteller (mbr:applicant). | Una domanda di ammissione richiede esattamente un richiedente (mbr:applicant). | Una solicitud de ingreso necesita exactamente un solicitante (mbr:applicant). | Um pedido de admissão precisa de exatamente um requerente (mbr:applicant). | Egy felvételi kérelemnek pontosan egy kérelmezője kell legyen (mbr:applicant). | Μια αίτηση εισδοχής χρειάζεται ακριβώς έναν αιτούντα (mbr:applicant). | Een aanvraag tot lidmaatschap heeft precies één aanvrager nodig (mbr:applicant)." ] ,
                [ sh:path mbr:appliedTo ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ;
                  sh:message "A membership application needs exactly one organisation it is addressed to (mbr:appliedTo). | En medlemsansökan behöver exakt en organisation den riktas till (mbr:appliedTo). | Une demande d'adhésion a besoin d'exactement une organisation destinataire (mbr:appliedTo). | Ein Mitgliedschaftsantrag braucht genau eine Organisation, an die er gerichtet ist (mbr:appliedTo). | Una domanda di ammissione richiede esattamente un'organizzazione destinataria (mbr:appliedTo). | Una solicitud de ingreso necesita exactamente una organización destinataria (mbr:appliedTo). | Um pedido de admissão precisa de exatamente uma organização destinatária (mbr:appliedTo). | Egy felvételi kérelemnek pontosan egy címzett szervezete kell legyen (mbr:appliedTo). | Μια αίτηση εισδοχής χρειάζεται ακριβώς μία οργάνωση προς την οποία απευθύνεται (mbr:appliedTo). | Een aanvraag tot lidmaatschap heeft precies één organisatie nodig waaraan ze is gericht (mbr:appliedTo)." ] ,
                [ sh:path mbr:applicationStatus ; sh:minCount 1 ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:ApplicationStatusValue ;
                  sh:message "mbr:applicationStatus must be exactly one concept in mbrc:ApplicationStatuses, or one mapped to it. | mbr:applicationStatus ska vara exakt ett begrepp i mbrc:ApplicationStatuses, eller ett som är mappat dit. | mbr:applicationStatus doit être exactement un concept de mbrc:ApplicationStatuses, ou un concept qui y est mis en correspondance. | mbr:applicationStatus muss genau ein Konzept in mbrc:ApplicationStatuses sein, oder eines, das darauf abgebildet ist. | mbr:applicationStatus deve essere esattamente un concetto di mbrc:ApplicationStatuses, o uno mappato su di esso. | mbr:applicationStatus debe ser exactamente un concepto de mbrc:ApplicationStatuses, o uno asociado a él. | mbr:applicationStatus tem de ser exatamente um conceito de mbrc:ApplicationStatuses, ou um associado a ele. | Az mbr:applicationStatus értéke pontosan egy fogalom az mbrc:ApplicationStatuses-ból, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:applicationStatus πρέπει να είναι ακριβώς μία έννοια του mbrc:ApplicationStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:applicationStatus moet precies één concept in mbrc:ApplicationStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:resultingMembership ; sh:maxCount 1 ; sh:class org:Membership ] ,
                [ sh:path mbr:proposer ; sh:class foaf:Agent ] ,
                [ sh:path mbr:seconder ; sh:class foaf:Agent ] ;
    # org:member is for a Membership; an applicant is not yet a member.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "A membership application has mbr:applicant, not org:member (org:member is for a membership). | En medlemsansökan har mbr:applicant, inte org:member (org:member hör till ett medlemskap). | Une demande d'adhésion a mbr:applicant, pas org:member (org:member est pour une adhésion). | Ein Mitgliedschaftsantrag hat mbr:applicant, nicht org:member (org:member gehört zu einer Mitgliedschaft). | Una domanda di ammissione ha mbr:applicant, non org:member (org:member è per un'appartenenza). | Una solicitud de ingreso tiene mbr:applicant, no org:member (org:member es para una pertenencia). | Um pedido de admissão tem mbr:applicant, não org:member (org:member é para uma filiação). | A felvételi kérelemnek mbr:applicant van, nem org:member (az org:member tagságra szolgál). | Μια αίτηση εισδοχής έχει mbr:applicant, όχι org:member (το org:member προορίζεται για ιδιότητα μέλους). | Een aanvraag tot lidmaatschap heeft mbr:applicant, geen org:member (org:member is voor een lidmaatschap)." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?m WHERE { $this org:member ?m . }
        """
    ] .

mbrsh:BallotShape a sh:NodeShape ;
    sh:targetClass mbr:Ballot ;
    sh:property [ sh:path mbr:ballotOn ; sh:minCount 1 ; sh:maxCount 1 ; sh:class mbr:MembershipApplication ;
                  sh:message "A ballot needs exactly one application it is held on (mbr:ballotOn). | En ballotering behöver exakt en ansökan den gäller (mbr:ballotOn). | Un scrutin a besoin d'exactement une demande sur laquelle il porte (mbr:ballotOn). | Eine Abstimmung braucht genau einen Antrag, über den abgestimmt wird (mbr:ballotOn). | Una votazione richiede esattamente una domanda su cui si tiene (mbr:ballotOn). | Una votación necesita exactamente una solicitud sobre la que se celebra (mbr:ballotOn). | Uma votação precisa de exatamente um pedido sobre o qual se realiza (mbr:ballotOn). | Egy szavazásnak pontosan egy kérelme kell legyen, amelyről szól (mbr:ballotOn). | Μια ψηφοφορία χρειάζεται ακριβώς μία αίτηση για την οποία διεξάγεται (mbr:ballotOn). | Een ballotage heeft precies één aanvraag nodig waarover ze wordt gehouden (mbr:ballotOn)." ] ,
                [ sh:path mbr:votesFor ; sh:maxCount 1 ; sh:node mbrsh:CountList ;
                  sh:message "mbr:votesFor must be one non-negative integer. | mbr:votesFor ska vara ett enda icke-negativt heltal. | mbr:votesFor doit être un seul entier non négatif. | mbr:votesFor muss eine einzige nichtnegative ganze Zahl sein. | mbr:votesFor deve essere un solo intero non negativo. | mbr:votesFor debe ser un único entero no negativo. | mbr:votesFor tem de ser um único inteiro não negativo. | Az mbr:votesFor értéke egyetlen nemnegatív egész szám kell legyen. | Το mbr:votesFor πρέπει να είναι ένας μη αρνητικός ακέραιος. | mbr:votesFor moet één niet-negatief geheel getal zijn." ] ,
                [ sh:path mbr:votesAgainst ; sh:maxCount 1 ; sh:node mbrsh:CountList ;
                  sh:message "mbr:votesAgainst must be one non-negative integer. | mbr:votesAgainst ska vara ett enda icke-negativt heltal. | mbr:votesAgainst doit être un seul entier non négatif. | mbr:votesAgainst muss eine einzige nichtnegative ganze Zahl sein. | mbr:votesAgainst deve essere un solo intero non negativo. | mbr:votesAgainst debe ser un único entero no negativo. | mbr:votesAgainst tem de ser um único inteiro não negativo. | Az mbr:votesAgainst értéke egyetlen nemnegatív egész szám kell legyen. | Το mbr:votesAgainst πρέπει να είναι ένας μη αρνητικός ακέραιος. | mbr:votesAgainst moet één niet-negatief geheel getal zijn." ] .

##############################################################################
# Charters and changes of organisation
##############################################################################

mbrsh:CharterShape a sh:NodeShape ;
    sh:targetClass mbr:Charter ;
    sh:property [ sh:path mbr:issuedBy ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ;
                  sh:message "A charter needs exactly one issuing organisation (mbr:issuedBy). | Ett stiftelsebrev behöver exakt en utfärdande organisation (mbr:issuedBy). | Une charte a besoin d'exactement une organisation émettrice (mbr:issuedBy). | Eine Urkunde braucht genau eine ausstellende Organisation (mbr:issuedBy). | Una carta richiede esattamente un'organizzazione emittente (mbr:issuedBy). | Una carta constitutiva necesita exactamente una organización emisora (mbr:issuedBy). | Uma carta constitutiva precisa de exatamente uma organização emissora (mbr:issuedBy). | Egy alapítólevélnek pontosan egy kiállító szervezete kell legyen (mbr:issuedBy). | Ένας ιδρυτικός χάρτης χρειάζεται ακριβώς μία εκδούσα οργάνωση (mbr:issuedBy). | Een charter heeft precies één verlenende organisatie nodig (mbr:issuedBy)." ] ,
                [ sh:path mbr:issuedTo ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ;
                  sh:message "A charter needs exactly one organisation that holds it (mbr:issuedTo). | Ett stiftelsebrev behöver exakt en organisation som innehar det (mbr:issuedTo). | Une charte a besoin d'exactement une organisation qui la détient (mbr:issuedTo). | Eine Urkunde braucht genau eine Organisation, die sie innehat (mbr:issuedTo). | Una carta richiede esattamente un'organizzazione che la detiene (mbr:issuedTo). | Una carta constitutiva necesita exactamente una organización que la posea (mbr:issuedTo). | Uma carta constitutiva precisa de exatamente uma organização que a detenha (mbr:issuedTo). | Egy alapítólevélnek pontosan egy szervezete kell legyen, amely birtokolja (mbr:issuedTo). | Ένας ιδρυτικός χάρτης χρειάζεται ακριβώς μία οργάνωση που τον κατέχει (mbr:issuedTo). | Een charter heeft precies één organisatie nodig die het houdt (mbr:issuedTo)." ] ,
                [ sh:path mbr:charterStatus ; sh:minCount 1 ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:CharterStatusValue ;
                  sh:message "mbr:charterStatus must be exactly one concept in mbrc:CharterStatuses, or one mapped to it. | mbr:charterStatus ska vara exakt ett begrepp i mbrc:CharterStatuses, eller ett som är mappat dit. | mbr:charterStatus doit être exactement un concept de mbrc:CharterStatuses, ou un concept qui y est mis en correspondance. | mbr:charterStatus muss genau ein Konzept in mbrc:CharterStatuses sein, oder eines, das darauf abgebildet ist. | mbr:charterStatus deve essere esattamente un concetto di mbrc:CharterStatuses, o uno mappato su di esso. | mbr:charterStatus debe ser exactamente un concepto de mbrc:CharterStatuses, o uno asociado a él. | mbr:charterStatus tem de ser exatamente um conceito de mbrc:CharterStatuses, ou um associado a ele. | Az mbr:charterStatus értéke pontosan egy fogalom az mbrc:CharterStatuses-ból, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:charterStatus πρέπει να είναι ακριβώς μία έννοια του mbrc:CharterStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:charterStatus moet precies één concept in mbrc:CharterStatuses zijn, of een concept dat daarop is afgebeeld." ] ;
    # A body does not charter itself.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "A charter cannot be issued by the organisation that holds it (mbr:issuedBy and mbr:issuedTo are the same). | Ett stiftelsebrev kan inte utfärdas av den organisation som innehar det (mbr:issuedBy och mbr:issuedTo är samma). | Une charte ne peut pas être délivrée par l'organisation qui la détient (mbr:issuedBy et mbr:issuedTo sont identiques). | Eine Urkunde kann nicht von der Organisation ausgestellt werden, die sie innehat (mbr:issuedBy und mbr:issuedTo sind dieselbe). | Una carta non può essere rilasciata dall'organizzazione che la detiene (mbr:issuedBy e mbr:issuedTo coincidono). | Una carta constitutiva no puede ser expedida por la organización que la posee (mbr:issuedBy y mbr:issuedTo son la misma). | Uma carta constitutiva não pode ser emitida pela organização que a detém (mbr:issuedBy e mbr:issuedTo são a mesma). | Az alapítólevelet nem állíthatja ki az a szervezet, amely birtokolja (az mbr:issuedBy és az mbr:issuedTo azonos). | Ένας ιδρυτικός χάρτης δεν μπορεί να εκδοθεί από την οργάνωση που τον κατέχει (τα mbr:issuedBy και mbr:issuedTo είναι τα ίδια). | Een charter kan niet worden verleend door de organisatie die het houdt (mbr:issuedBy en mbr:issuedTo zijn gelijk)." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?o WHERE { $this mbr:issuedBy ?o ; mbr:issuedTo ?o . }
        """
    ] .

mbrsh:ChangeEventShape a sh:NodeShape ;
    sh:targetClass org:ChangeEvent ;
    sh:property [ sh:path mbr:changeEventType ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:ChangeEventTypeValue ;
                  sh:message "mbr:changeEventType must be one concept in mbrc:ChangeEventTypes, or one mapped to it. | mbr:changeEventType ska vara ett begrepp i mbrc:ChangeEventTypes, eller ett som är mappat dit. | mbr:changeEventType doit être un concept de mbrc:ChangeEventTypes, ou un concept qui y est mis en correspondance. | mbr:changeEventType muss ein Konzept in mbrc:ChangeEventTypes sein, oder eines, das darauf abgebildet ist. | mbr:changeEventType deve essere un concetto di mbrc:ChangeEventTypes, o uno mappato su di esso. | mbr:changeEventType debe ser un concepto de mbrc:ChangeEventTypes, o uno asociado a él. | mbr:changeEventType tem de ser um conceito de mbrc:ChangeEventTypes, ou um associado a ele. | Az mbr:changeEventType értéke az mbrc:ChangeEventTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:changeEventType πρέπει να είναι μία έννοια του mbrc:ChangeEventTypes, ή αντιστοιχισμένη σε αυτό. | mbr:changeEventType moet één concept in mbrc:ChangeEventTypes zijn, of een concept dat daarop is afgebeeld." ] .

##############################################################################
# Membership fees
##############################################################################

mbrsh:AmountList
    sh:or ( [ sh:datatype xsd:decimal ] [ sh:datatype xsd:integer ] ) .

mbrsh:MembershipFeeLinkShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:membershipFee ;
    sh:property [ sh:path mbr:membershipFee ; sh:class mbr:MembershipFee ] .

mbrsh:MembershipFeeShape a sh:NodeShape ;
    sh:targetClass mbr:MembershipFee ;
    sh:property [ sh:path mbr:feeType ; sh:minCount 1 ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:FeeTypeValue ;
                  sh:message "A membership fee needs exactly one mbr:feeType from mbrc:FeeTypes, or a concept mapped to it. | En medlemsavgift behöver exakt en mbr:feeType från mbrc:FeeTypes, eller ett begrepp som är mappat dit. | Une cotisation a besoin d'exactement un mbr:feeType de mbrc:FeeTypes, ou d'un concept qui y est mappé. | Ein Mitgliedsbeitrag braucht genau einen mbr:feeType aus mbrc:FeeTypes oder ein darauf abgebildetes Konzept. | Una quota associativa richiede esattamente un mbr:feeType di mbrc:FeeTypes, o un concetto associato a esso. | Una cuota de socio necesita exactamente un mbr:feeType de mbrc:FeeTypes, o un concepto asociado a él. | Uma quota precisa de exatamente um mbr:feeType de mbrc:FeeTypes, ou de um conceito associado a ele. | Egy tagdíjnak pontosan egy mbr:feeType értéke kell legyen az mbrc:FeeTypes-ból, vagy egy hozzárendelt fogalom. | Μια συνδρομή μέλους χρειάζεται ακριβώς ένα mbr:feeType από το mbrc:FeeTypes, ή μια έννοια αντιστοιχισμένη σε αυτό. | Een contributie heeft precies één mbr:feeType uit mbrc:FeeTypes nodig, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path schema:price ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:node mbrsh:AmountList ; sh:minInclusive 0 ;
                  sh:message "A membership fee needs exactly one schema:price, a number of zero or more. | En medlemsavgift behöver exakt ett schema:price, ett tal som är noll eller större. | Une cotisation a besoin d'exactement un schema:price, un nombre supérieur ou égal à zéro. | Ein Mitgliedsbeitrag braucht genau einen schema:price, eine Zahl von null oder mehr. | Una quota associativa richiede esattamente un schema:price, un numero pari o superiore a zero. | Una cuota de socio necesita exactamente un schema:price, un número igual o mayor que cero. | Uma quota precisa de exatamente um schema:price, um número igual ou superior a zero. | Egy tagdíjnak pontosan egy schema:price értéke kell legyen, nullánál nem kisebb szám. | Μια συνδρομή μέλους χρειάζεται ακριβώς ένα schema:price, έναν αριθμό μηδέν ή μεγαλύτερο. | Een contributie heeft precies één schema:price nodig, een getal van nul of meer." ] ,
                [ sh:path schema:priceCurrency ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:datatype xsd:string ; sh:pattern "^[A-Z]{3}$" ;
                  sh:message "schema:priceCurrency must be a three-letter ISO 4217 code such as SEK or GBP. | schema:priceCurrency ska vara en trebokstavskod enligt ISO 4217, t.ex. SEK eller GBP. | schema:priceCurrency doit être un code ISO 4217 de trois lettres, comme SEK ou GBP. | schema:priceCurrency muss ein dreibuchstabiger ISO-4217-Code wie SEK oder GBP sein. | schema:priceCurrency deve essere un codice ISO 4217 di tre lettere come SEK o GBP. | schema:priceCurrency debe ser un código ISO 4217 de tres letras como SEK o GBP. | schema:priceCurrency tem de ser um código ISO 4217 de três letras como SEK ou GBP. | A schema:priceCurrency értéke hárombetűs ISO 4217 kód kell legyen, például SEK vagy GBP. | Το schema:priceCurrency πρέπει να είναι τριγράμματος κωδικός ISO 4217 όπως SEK ή GBP. | schema:priceCurrency moet een ISO 4217-code van drie letters zijn, zoals SEK of GBP." ] ,
                [ sh:path mbr:appliesToCategory ; sh:class skos:Concept ;
                  sh:node mbrsh:MembershipCategoryValue ;
                  sh:message "mbr:appliesToCategory must be a concept in mbrc:MembershipCategories, or one mapped to it. | mbr:appliesToCategory ska vara ett begrepp i mbrc:MembershipCategories, eller ett som är mappat dit. | mbr:appliesToCategory doit être un concept de mbrc:MembershipCategories, ou un concept qui y est mappé. | mbr:appliesToCategory muss ein Konzept aus mbrc:MembershipCategories sein oder eines, das darauf abgebildet ist. | mbr:appliesToCategory deve essere un concetto di mbrc:MembershipCategories, o uno associato a esso. | mbr:appliesToCategory debe ser un concepto de mbrc:MembershipCategories, o uno asociado a él. | mbr:appliesToCategory tem de ser um conceito de mbrc:MembershipCategories, ou um associado a ele. | Az mbr:appliesToCategory értéke az mbrc:MembershipCategories egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:appliesToCategory πρέπει να είναι έννοια του mbrc:MembershipCategories, ή αντιστοιχισμένη σε αυτό. | mbr:appliesToCategory moet een concept in mbrc:MembershipCategories zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:startDate ; sh:minCount 1 ; sh:severity sh:Warning ;
                  sh:message "Give the date from which the fee applies (mbr:startDate). | Ange från vilket datum avgiften gäller (mbr:startDate). | Indiquer la date à partir de laquelle la cotisation s'applique (mbr:startDate). | Das Datum angeben, ab dem der Beitrag gilt (mbr:startDate). | Indicare la data da cui si applica la quota (mbr:startDate). | Indique la fecha desde la que se aplica la cuota (mbr:startDate). | Indique a data a partir da qual se aplica a quota (mbr:startDate). | Adja meg a dátumot, amelytől a díj érvényes (mbr:startDate). | Δώστε την ημερομηνία από την οποία ισχύει η συνδρομή (mbr:startDate). | Geef de datum vanaf wanneer de contributie geldt (mbr:startDate)." ] .

##############################################################################
# Offices and terms of office
##############################################################################

mbrsh:TenureShape a sh:NodeShape ;
    sh:targetClass mbr:Tenure ;
    sh:property [ sh:path org:member ; sh:minCount 1 ; sh:maxCount 1 ; sh:class foaf:Agent ] ,
                [ sh:path org:organization ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ] ,
                [ sh:path org:role ; sh:minCount 1 ; sh:maxCount 1 ; sh:class mbr:Office ;
                  sh:message "A term of office needs exactly one org:role that is a mbr:Office. | En ämbetsperiod behöver exakt en org:role som är ett mbr:Office. | Un mandat a besoin d'exactement un org:role qui est un mbr:Office. | Eine Amtszeit braucht genau eine org:role, die ein mbr:Office ist. | Un mandato richiede esattamente un org:role che sia un mbr:Office. | Un mandato necesita exactamente un org:role que sea un mbr:Office. | Um mandato precisa de exatamente um org:role que seja um mbr:Office. | Egy megbízatásnak pontosan egy org:role értéke kell legyen, amely mbr:Office. | Μια θητεία χρειάζεται ακριβώς έναν org:role που είναι mbr:Office. | Een ambtstermijn heeft precies één org:role nodig die een mbr:Office is." ] ,
                [ sh:path org:role ; sh:node mbrsh:OfficeTypeValue ;
                  sh:message "org:role must be a concept in mbrc:OfficeTypes, or one mapped to it. | org:role ska vara ett begrepp i mbrc:OfficeTypes, eller ett som är mappat dit. | org:role doit être un concept de mbrc:OfficeTypes, ou un concept qui y est associé. | org:role muss ein Konzept aus mbrc:OfficeTypes sein oder eines, das darauf abgebildet ist. | org:role deve essere un concetto di mbrc:OfficeTypes, o uno associato a esso. | org:role debe ser un concepto de mbrc:OfficeTypes, o uno asociado a él. | org:role tem de ser um conceito de mbrc:OfficeTypes, ou um associado a ele. | Az org:role értéke az mbrc:OfficeTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το org:role πρέπει να είναι έννοια του mbrc:OfficeTypes, ή αντιστοιχισμένη σε αυτό. | org:role moet een concept in mbrc:OfficeTypes zijn, of een concept dat daarop is afgebeeld." ] .

##############################################################################
# Gatherings and participation
##############################################################################

mbrsh:GatheringShape a sh:NodeShape ;
    sh:targetClass mbr:Gathering ;
    sh:property [ sh:path mbr:gatheringType ; sh:minCount 1 ; sh:class skos:Concept ;
                  sh:severity sh:Warning ] ,
                [ sh:path mbr:gatheringType ; sh:node mbrsh:GatheringTypeValue ;
                  sh:message "mbr:gatheringType must be a concept in mbrc:GatheringTypes, or one mapped to it. | mbr:gatheringType ska vara ett begrepp i mbrc:GatheringTypes, eller ett som är mappat dit. | mbr:gatheringType doit être un concept de mbrc:GatheringTypes, ou un concept qui y est mappé. | mbr:gatheringType muss ein Konzept aus mbrc:GatheringTypes sein oder eines, das darauf abgebildet ist. | mbr:gatheringType deve essere un concetto di mbrc:GatheringTypes, o uno associato a esso. | mbr:gatheringType debe ser un concepto de mbrc:GatheringTypes, o uno asociado a él. | mbr:gatheringType tem de ser um conceito de mbrc:GatheringTypes, ou um associado a ele. | Az mbr:gatheringType értéke az mbrc:GatheringTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:gatheringType πρέπει να είναι έννοια του mbrc:GatheringTypes, ή αντιστοιχισμένη σε αυτό. | mbr:gatheringType moet een concept in mbrc:GatheringTypes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:startDate ; sh:minCount 1 ; sh:severity sh:Warning ] ,
                [ sh:path mbr:organizer ; sh:class foaf:Agent ] ,
                [ sh:path mbr:dressCode ; sh:class skos:Concept ; sh:node mbrsh:DressCodeValue ;
                  sh:message "mbr:dressCode must be a concept in mbrc:DressCodes, or one mapped to it. | mbr:dressCode ska vara ett begrepp i mbrc:DressCodes, eller ett som är mappat dit. | mbr:dressCode doit être un concept de mbrc:DressCodes, ou un concept qui y est mappé. | mbr:dressCode muss ein Konzept aus mbrc:DressCodes sein oder eines, das darauf abgebildet ist. | mbr:dressCode deve essere un concetto di mbrc:DressCodes, o uno associato a esso. | mbr:dressCode debe ser un concepto de mbrc:DressCodes, o uno asociado a él. | mbr:dressCode tem de ser um conceito de mbrc:DressCodes, ou um associado a ele. | Az mbr:dressCode értéke az mbrc:DressCodes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:dressCode πρέπει να είναι έννοια του mbrc:DressCodes, ή αντιστοιχισμένη σε αυτό. | mbr:dressCode moet een concept in mbrc:DressCodes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path schema:superEvent ; sh:maxCount 1 ; sh:class schema:Event ] .

mbrsh:ParticipationShape a sh:NodeShape ;
    sh:targetClass mbr:Participation ;
    sh:property [ sh:path mbr:participant ; sh:minCount 1 ; sh:maxCount 1 ; sh:class foaf:Agent ] ,
                [ sh:path mbr:participationIn ; sh:minCount 1 ; sh:maxCount 1 ; sh:class schema:Event ] ,
                [ sh:path mbr:participationRole ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:ParticipationRoleValue ;
                  sh:message "mbr:participationRole must be a concept in mbrc:ParticipationRoles, or one mapped to it. | mbr:participationRole ska vara ett begrepp i mbrc:ParticipationRoles, eller ett som är mappat dit. | mbr:participationRole doit être un concept de mbrc:ParticipationRoles, ou un concept qui y est mappé. | mbr:participationRole muss ein Konzept aus mbrc:ParticipationRoles sein oder eines, das darauf abgebildet ist. | mbr:participationRole deve essere un concetto di mbrc:ParticipationRoles, o uno associato a esso. | mbr:participationRole debe ser un concepto de mbrc:ParticipationRoles, o uno asociado a él. | mbr:participationRole tem de ser um conceito de mbrc:ParticipationRoles, ou um associado a ele. | Az mbr:participationRole értéke az mbrc:ParticipationRoles egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:participationRole πρέπει να είναι έννοια του mbrc:ParticipationRoles, ή αντιστοιχισμένη σε αυτό. | mbr:participationRole moet een concept in mbrc:ParticipationRoles zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:introducedBy ; sh:maxCount 1 ; sh:class foaf:Agent ] .

##############################################################################
# Distinctions and conferrals
##############################################################################

mbrsh:DistinctionShape a sh:NodeShape ;
    sh:targetClass mbr:Distinction ;
    sh:property [ sh:path skos:inScheme ; sh:minCount 1 ] ,
                [ sh:path mbr:distinctionType ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:DistinctionTypeValue ;
                  sh:message "mbr:distinctionType must be a concept in mbrc:DistinctionTypes, or one mapped to it. | mbr:distinctionType ska vara ett begrepp i mbrc:DistinctionTypes, eller ett som är mappat dit. | mbr:distinctionType doit être un concept de mbrc:DistinctionTypes, ou un concept qui y est mappé. | mbr:distinctionType muss ein Konzept aus mbrc:DistinctionTypes sein oder eines, das darauf abgebildet ist. | mbr:distinctionType deve essere un concetto di mbrc:DistinctionTypes, o uno associato a esso. | mbr:distinctionType debe ser un concepto de mbrc:DistinctionTypes, o uno asociado a él. | mbr:distinctionType tem de ser um conceito de mbrc:DistinctionTypes, ou um associado a ele. | Az mbr:distinctionType értéke az mbrc:DistinctionTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:distinctionType πρέπει να είναι έννοια του mbrc:DistinctionTypes, ή αντιστοιχισμένη σε αυτό. | mbr:distinctionType moet een concept in mbrc:DistinctionTypes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:material ; sh:class skos:Concept ;
                  sh:node mbrsh:MaterialValue ;
                  sh:message "mbr:material must be a concept in mbrc:Materials, or one mapped to it. | mbr:material ska vara ett begrepp i mbrc:Materials, eller ett som är mappat dit. | mbr:material doit être un concept de mbrc:Materials, ou un concept qui y est mappé. | mbr:material muss ein Konzept aus mbrc:Materials sein oder eines, das darauf abgebildet ist. | mbr:material deve essere un concetto di mbrc:Materials, o uno associato a esso. | mbr:material debe ser un concepto de mbrc:Materials, o uno asociado a él. | mbr:material tem de ser um conceito de mbrc:Materials, ou um associado a ele. | Az mbr:material értéke az mbrc:Materials egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:material πρέπει να είναι έννοια του mbrc:Materials, ή αντιστοιχισμένη σε αυτό. | mbr:material moet een concept in mbrc:Materials zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:ribbonColour ; sh:maxCount 1 ; sh:class skos:Concept ] .

mbrsh:ConferralShape a sh:NodeShape ;
    sh:targetClass mbr:Conferral ;
    sh:property [ sh:path mbr:recipient ; sh:minCount 1 ; sh:class foaf:Agent ] ,
                [ sh:path mbr:conferred ; sh:minCount 1 ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:message "A conferral needs exactly one conferred concept (distinction or degree). | En tilldelning behöver exakt ett tilldelat begrepp (utmärkelse eller grad). | Une attribution a besoin d'exactement un concept conféré (distinction ou degré). | Eine Verleihung braucht genau ein verliehenes Konzept (Auszeichnung oder Grad). | Un conferimento richiede esattamente un concetto conferito (riconoscimento o grado). | Una concesión necesita exactamente un concepto conferido (distinción o grado). | Uma atribuição precisa de exatamente um conceito conferido (distinção ou grau). | Egy adományozásnak pontosan egy odaítélt fogalma kell legyen (kitüntetés vagy fokozat). | Μια απονομή χρειάζεται ακριβώς μία έννοια που απονέμεται (διάκριση ή βαθμός). | Een verlening heeft precies één verleend concept nodig (onderscheiding of graad)." ] ,
                [ sh:path mbr:conferredAt ; sh:maxCount 1 ; sh:class schema:Event ] ,
                [ sh:path mbr:conferredBy ; sh:maxCount 1 ; sh:class foaf:Agent ] .

mbrsh:DistinctionConferralShape a sh:NodeShape ;
    sh:targetClass mbr:DistinctionConferral ;
    sh:property [ sh:path mbr:conferred ; sh:class mbr:Distinction ] .

##############################################################################
# Organisations and concepts
##############################################################################

mbrsh:OrganizationShape a sh:NodeShape ;
    sh:targetClass mbr:MembershipOrganization ;
    sh:property [ sh:path org:classification ; sh:minCount 1 ; sh:class skos:Concept ;
                  sh:severity sh:Warning ] ,
                [ sh:path org:classification ; sh:node mbrsh:OrganizationTypeValue ;
                  sh:message "org:classification must be a concept in mbrc:OrganizationTypes, or one mapped to it. | org:classification ska vara ett begrepp i mbrc:OrganizationTypes, eller ett som är mappat dit. | org:classification doit être un concept de mbrc:OrganizationTypes, ou un concept qui y est mappé. | org:classification muss ein Konzept aus mbrc:OrganizationTypes sein oder eines, das darauf abgebildet ist. | org:classification deve essere un concetto di mbrc:OrganizationTypes, o uno associato a esso. | org:classification debe ser un concepto de mbrc:OrganizationTypes, o uno asociado a él. | org:classification tem de ser um conceito de mbrc:OrganizationTypes, ou um associado a ele. | Az org:classification értéke az mbrc:OrganizationTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το org:classification πρέπει να είναι έννοια του mbrc:OrganizationTypes, ή αντιστοιχισμένη σε αυτό. | org:classification moet een concept in mbrc:OrganizationTypes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:genderPolicy ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:GenderPolicyValue ;
                  sh:message "mbr:genderPolicy must be a concept in mbrc:GenderPolicies, or one mapped to it. | mbr:genderPolicy ska vara ett begrepp i mbrc:GenderPolicies, eller ett som är mappat dit. | mbr:genderPolicy doit être un concept de mbrc:GenderPolicies, ou un concept qui y est mappé. | mbr:genderPolicy muss ein Konzept aus mbrc:GenderPolicies sein oder eines, das darauf abgebildet ist. | mbr:genderPolicy deve essere un concetto di mbrc:GenderPolicies, o uno associato a esso. | mbr:genderPolicy debe ser un concepto de mbrc:GenderPolicies, o uno asociado a él. | mbr:genderPolicy tem de ser um conceito de mbrc:GenderPolicies, ou um associado a ele. | Az mbr:genderPolicy értéke az mbrc:GenderPolicies egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:genderPolicy πρέπει να είναι έννοια του mbrc:GenderPolicies, ή αντιστοιχισμένη σε αυτό. | mbr:genderPolicy moet een concept in mbrc:GenderPolicies zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:admissionMode ; sh:class skos:Concept ;
                  sh:node mbrsh:AdmissionModeValue ;
                  sh:message "mbr:admissionMode must be a concept in mbrc:AdmissionModes, or one mapped to it. | mbr:admissionMode ska vara ett begrepp i mbrc:AdmissionModes, eller ett som är mappat dit. | mbr:admissionMode doit être un concept de mbrc:AdmissionModes, ou un concept qui y est mappé. | mbr:admissionMode muss ein Konzept aus mbrc:AdmissionModes sein oder eines, das darauf abgebildet ist. | mbr:admissionMode deve essere un concetto di mbrc:AdmissionModes, o uno associato a esso. | mbr:admissionMode debe ser un concepto de mbrc:AdmissionModes, o uno asociado a él. | mbr:admissionMode tem de ser um conceito de mbrc:AdmissionModes, ou um associado a ele. | Az mbr:admissionMode értéke az mbrc:AdmissionModes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:admissionMode πρέπει να είναι έννοια του mbrc:AdmissionModes, ή αντιστοιχισμένη σε αυτό. | mbr:admissionMode moet een concept in mbrc:AdmissionModes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:reciprocalWith ; sh:class org:Organization ] ,
                [ sh:path mbr:organizationStatus ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:OrganizationStatusValue ;
                  sh:message "mbr:organizationStatus must be a concept in mbrc:OrganizationStatuses, or one mapped to it. | mbr:organizationStatus ska vara ett begrepp i mbrc:OrganizationStatuses, eller ett som är mappat dit. | mbr:organizationStatus doit être un concept de mbrc:OrganizationStatuses, ou un concept qui y est mappé. | mbr:organizationStatus muss ein Konzept aus mbrc:OrganizationStatuses sein oder eines, das darauf abgebildet ist. | mbr:organizationStatus deve essere un concetto di mbrc:OrganizationStatuses, o uno associato a esso. | mbr:organizationStatus debe ser un concepto de mbrc:OrganizationStatuses, o uno asociado a él. | mbr:organizationStatus tem de ser um conceito de mbrc:OrganizationStatuses, ou um associado a ele. | Az mbr:organizationStatus értéke az mbrc:OrganizationStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:organizationStatus πρέπει να είναι έννοια του mbrc:OrganizationStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:organizationStatus moet een concept in mbrc:OrganizationStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path rov:orgType ; sh:class skos:Concept ;
                  sh:node mbrsh:LegalFormValue ;
                  sh:message "rov:orgType must be a concept in mbrc:LegalForms, or one mapped to it. | rov:orgType ska vara ett begrepp i mbrc:LegalForms, eller ett som är mappat dit. | rov:orgType doit être un concept de mbrc:LegalForms, ou un concept qui y est mappé. | rov:orgType muss ein Konzept aus mbrc:LegalForms sein oder eines, das darauf abgebildet ist. | rov:orgType deve essere un concetto di mbrc:LegalForms, o uno associato a esso. | rov:orgType debe ser un concepto de mbrc:LegalForms, o uno asociado a él. | rov:orgType tem de ser um conceito de mbrc:LegalForms, ou um associado a ele. | A rov:orgType értéke az mbrc:LegalForms egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το rov:orgType πρέπει να είναι έννοια του mbrc:LegalForms, ή αντιστοιχισμένη σε αυτό. | rov:orgType moet een concept in mbrc:LegalForms zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:publicBenefitStatus ; sh:class skos:Concept ;
                  sh:node mbrsh:PublicBenefitStatusValue ;
                  sh:message "mbr:publicBenefitStatus must be a concept in mbrc:PublicBenefitStatuses, or one mapped to it. | mbr:publicBenefitStatus ska vara ett begrepp i mbrc:PublicBenefitStatuses, eller ett som är mappat dit. | mbr:publicBenefitStatus doit être un concept de mbrc:PublicBenefitStatuses, ou un concept qui y est associé. | mbr:publicBenefitStatus muss ein Konzept aus mbrc:PublicBenefitStatuses sein oder eines, das darauf abgebildet ist. | mbr:publicBenefitStatus deve essere un concetto di mbrc:PublicBenefitStatuses, o uno associato a esso. | mbr:publicBenefitStatus debe ser un concepto de mbrc:PublicBenefitStatuses, o uno asociado a él. | mbr:publicBenefitStatus tem de ser um conceito de mbrc:PublicBenefitStatuses, ou um associado a ele. | Az mbr:publicBenefitStatus értéke az mbrc:PublicBenefitStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:publicBenefitStatus πρέπει να είναι έννοια του mbrc:PublicBenefitStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:publicBenefitStatus moet een concept in mbrc:PublicBenefitStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path rov:registration ; sh:class adms:Identifier ] ,
                [ sh:path mbr:ownershipModel ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:OwnershipModelValue ;
                  sh:message "mbr:ownershipModel must be a concept in mbrc:OwnershipModels, or one mapped to it. | mbr:ownershipModel ska vara ett begrepp i mbrc:OwnershipModels, eller ett som är mappat dit. | mbr:ownershipModel doit être un concept de mbrc:OwnershipModels, ou un concept qui y est mappé. | mbr:ownershipModel muss ein Konzept aus mbrc:OwnershipModels sein oder eines, das darauf abgebildet ist. | mbr:ownershipModel deve essere un concetto di mbrc:OwnershipModels, o uno associato a esso. | mbr:ownershipModel debe ser un concepto de mbrc:OwnershipModels, o uno asociado a él. | mbr:ownershipModel tem de ser um conceito de mbrc:OwnershipModels, ou um associado a ele. | Az mbr:ownershipModel értéke az mbrc:OwnershipModels egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:ownershipModel πρέπει να είναι έννοια του mbrc:OwnershipModels, ή αντιστοιχισμένη σε αυτό. | mbr:ownershipModel moet een concept in mbrc:OwnershipModels zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:hasMemberCount ; sh:class mbr:MemberCount ] ,
                [ sh:path mbr:dressCode ; sh:class skos:Concept ; sh:node mbrsh:DressCodeValue ;
                  sh:message "mbr:dressCode must be a concept in mbrc:DressCodes, or one mapped to it. | mbr:dressCode ska vara ett begrepp i mbrc:DressCodes, eller ett som är mappat dit. | mbr:dressCode doit être un concept de mbrc:DressCodes, ou un concept qui y est mappé. | mbr:dressCode muss ein Konzept aus mbrc:DressCodes sein oder eines, das darauf abgebildet ist. | mbr:dressCode deve essere un concetto di mbrc:DressCodes, o uno associato a esso. | mbr:dressCode debe ser un concepto de mbrc:DressCodes, o uno asociado a él. | mbr:dressCode tem de ser um conceito de mbrc:DressCodes, ou um associado a ele. | Az mbr:dressCode értéke az mbrc:DressCodes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:dressCode πρέπει να είναι έννοια του mbrc:DressCodes, ή αντιστοιχισμένη σε αυτό. | mbr:dressCode moet een concept in mbrc:DressCodes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path schema:url ; sh:nodeKind sh:IRI ;
                  sh:message "schema:url must be an IRI, e.g. <https://example.org/>. | schema:url ska vara en IRI, t.ex. <https://example.org/>. | schema:url doit être une IRI, par ex. <https://example.org/>. | schema:url muss eine IRI sein, z. B. <https://example.org/>. | schema:url deve essere un IRI, ad es. <https://example.org/>. | schema:url debe ser un IRI, p. ej. <https://example.org/>. | schema:url tem de ser um IRI, p. ex. <https://example.org/>. | A schema:url értéke IRI kell legyen, például <https://example.org/>. | Το schema:url πρέπει να είναι IRI, π.χ. <https://example.org/>. | schema:url moet een IRI zijn, bijv. <https://example.org/>." ] ,
                [ sh:path schema:email ; sh:datatype xsd:string ; sh:pattern "^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$" ;
                  sh:message "schema:email must be a plain e-mail address. | schema:email ska vara en e-postadress. | schema:email doit être une simple adresse e-mail. | schema:email muss eine einfache E-Mail-Adresse sein. | schema:email deve essere un semplice indirizzo e-mail. | schema:email debe ser una dirección de correo electrónico simple. | schema:email tem de ser um endereço de correio eletrónico simples. | A schema:email értéke egyszerű e-mail-cím kell legyen. | Το schema:email πρέπει να είναι απλή διεύθυνση ηλεκτρονικού ταχυδρομείου. | schema:email moet een gewoon e-mailadres zijn." ] ,
                [ sh:path schema:telephone ; sh:datatype xsd:string ] ;

    # A closed or merged organisation should not still be marked active.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "An organisation with a dissolution date cannot have status active. | En organisation med upplösningsdatum kan inte ha status verksam. | Une organisation ayant une date de dissolution ne peut pas avoir le statut en activité. | Eine Organisation mit Auflösungsdatum kann nicht den Status „aktiv“ haben. | Un'organizzazione con una data di scioglimento non può avere lo stato attivo. | Una organización con fecha de disolución no puede tener el estado activa. | Uma organização com data de dissolução não pode ter o estado ativa. | A megszűnési dátummal rendelkező szervezet állapota nem lehet működő. | Μια οργάνωση με ημερομηνία λύσης δεν μπορεί να έχει κατάσταση ενεργή. | Een organisatie met een datum van opheffing kan niet de status actief hebben." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this WHERE {
                $this mbr:dissolutionDate ?d ;
                      mbr:organizationStatus mbrc:activeOrganization .
            }
        """
    ] ;

    # Dissolution cannot come before founding; partial dates are compared as in
    # mbrsh:EndDateShape (an error only when certain).
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "The dissolution date is certainly before the founding date. | Upplösningsdatumet ligger säkert före grundningsdatumet. | La date de dissolution est certainement antérieure à la date de fondation. | Das Auflösungsdatum liegt sicher vor dem Gründungsdatum. | La data di scioglimento è certamente anteriore alla data di fondazione. | La fecha de disolución es con seguridad anterior a la fecha de fundación. | A data de dissolução é com certeza anterior à data de fundação. | A megszűnés dátuma biztosan korábbi az alapítás dátumánál. | Η ημερομηνία λύσης είναι σίγουρα πριν από την ημερομηνία ίδρυσης. | De datum van opheffing ligt zeker vóór de oprichtingsdatum." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this WHERE {
                $this mbr:foundingDate ?f ;
                      mbr:dissolutionDate ?d .
                FILTER (datatype(?f) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                        datatype(?d) IN (xsd:date, xsd:gYearMonth, xsd:gYear))
                FILTER (REGEX(STR(?f), "^[0-9]{4}") && REGEX(STR(?d), "^[0-9]{4}"))
                BIND (IF(datatype(?f) = xsd:date, SUBSTR(STR(?f), 1, 10),
                      IF(datatype(?f) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?f), 1, 7), "-01"),
                         CONCAT(SUBSTR(STR(?f), 1, 4), "-01-01"))) AS ?earliestFounding)
                BIND (IF(datatype(?d) = xsd:date, SUBSTR(STR(?d), 1, 10),
                      IF(datatype(?d) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?d), 1, 7), "-31"),
                         CONCAT(SUBSTR(STR(?d), 1, 4), "-12-31"))) AS ?latestDissolution)
                FILTER (?latestDissolution < ?earliestFounding)
            }
        """
    ] .

##############################################################################
# Periods of gender policy, admission mode, ownership model and status
##############################################################################

mbrsh:HasPeriodShape a sh:NodeShape ;
    sh:targetSubjectsOf mbr:hasPeriod ;
    sh:class org:Organization ;
    sh:property [ sh:path mbr:hasPeriod ; sh:class mbr:OrganizationPeriod ;
                  sh:message "mbr:hasPeriod must lead to an mbr:OrganizationPeriod. | mbr:hasPeriod ska leda till en mbr:OrganizationPeriod. | mbr:hasPeriod doit mener à une mbr:OrganizationPeriod. | mbr:hasPeriod muss auf eine mbr:OrganizationPeriod verweisen. | mbr:hasPeriod deve condurre a un mbr:OrganizationPeriod. | mbr:hasPeriod debe conducir a un mbr:OrganizationPeriod. | mbr:hasPeriod tem de conduzir a um mbr:OrganizationPeriod. | Az mbr:hasPeriod egy mbr:OrganizationPeriod-ra kell mutasson. | Το mbr:hasPeriod πρέπει να οδηγεί σε ένα mbr:OrganizationPeriod. | mbr:hasPeriod moet naar een mbr:OrganizationPeriod leiden." ] .

# Kept apart from the shape below: a sh:message on a shape replaces the messages of the
# SPARQL constraint in that shape.
mbrsh:OrganizationPeriodContentShape a sh:NodeShape ;
    sh:targetClass mbr:OrganizationPeriod ;
    sh:targetObjectsOf mbr:hasPeriod ;
    sh:or ( [ sh:path mbr:genderPolicy ; sh:minCount 1 ]
            [ sh:path mbr:admissionMode ; sh:minCount 1 ]
            [ sh:path mbr:ownershipModel ; sh:minCount 1 ]
            [ sh:path mbr:organizationStatus ; sh:minCount 1 ]
            [ sh:path mbr:organizationType ; sh:minCount 1 ]
            [ sh:path mbr:legalForm ; sh:minCount 1 ]
            [ sh:path mbr:publicBenefitStatus ; sh:minCount 1 ] ) ;
    sh:message "A period needs at least one of mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm and mbr:publicBenefitStatus. | En period behöver minst en av mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm och mbr:publicBenefitStatus. | Une période a besoin d'au moins l'un de mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm et mbr:publicBenefitStatus. | Ein Zeitraum braucht mindestens eines von mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm und mbr:publicBenefitStatus. | Un periodo richiede almeno una tra mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm e mbr:publicBenefitStatus. | Un período necesita al menos una de las propiedades mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm y mbr:publicBenefitStatus. | Um período precisa de pelo menos uma das propriedades mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm e mbr:publicBenefitStatus. | Egy időszaknak legalább egyet tartalmaznia kell ezek közül: mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm és mbr:publicBenefitStatus. | Μια περίοδος χρειάζεται τουλάχιστον ένα από τα mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm και mbr:publicBenefitStatus. | Een periode heeft ten minste een van mbr:genderPolicy, mbr:admissionMode, mbr:ownershipModel, mbr:organizationStatus, mbr:organizationType, mbr:legalForm en mbr:publicBenefitStatus nodig." .

mbrsh:OrganizationPeriodShape a sh:NodeShape ;
    sh:targetClass mbr:OrganizationPeriod ;
    sh:targetObjectsOf mbr:hasPeriod ;
    sh:property [ sh:path [ sh:inversePath mbr:hasPeriod ] ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:message "A period belongs to exactly one organisation, linked with mbr:hasPeriod. | En period hör till exakt en organisation, kopplad med mbr:hasPeriod. | Une période appartient à exactement une organisation, reliée par mbr:hasPeriod. | Ein Zeitraum gehört zu genau einer Organisation, verknüpft mit mbr:hasPeriod. | Un periodo appartiene a esattamente un'organizzazione, collegata con mbr:hasPeriod. | Un período pertenece a exactamente una organización, vinculada con mbr:hasPeriod. | Um período pertence a exatamente uma organização, ligada com mbr:hasPeriod. | Egy időszak pontosan egy szervezethez tartozik, az mbr:hasPeriod-dal kapcsolva. | Μια περίοδος ανήκει σε ακριβώς μία οργάνωση, συνδεδεμένη με το mbr:hasPeriod. | Een periode hoort bij precies één organisatie, gekoppeld met mbr:hasPeriod." ] ,
                [ sh:path mbr:genderPolicy ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:GenderPolicyValue ;
                  sh:message "mbr:genderPolicy must be one concept in mbrc:GenderPolicies, or one mapped to it. | mbr:genderPolicy ska vara ett begrepp i mbrc:GenderPolicies, eller ett som är mappat dit. | mbr:genderPolicy doit être un seul concept de mbrc:GenderPolicies, ou un concept qui y est mappé. | mbr:genderPolicy muss ein einzelnes Konzept aus mbrc:GenderPolicies sein oder eines, das darauf abgebildet ist. | mbr:genderPolicy deve essere un unico concetto di mbrc:GenderPolicies, o uno associato a esso. | mbr:genderPolicy debe ser un concepto de mbrc:GenderPolicies, o uno asociado a él. | mbr:genderPolicy tem de ser um conceito de mbrc:GenderPolicies, ou um associado a ele. | Az mbr:genderPolicy értéke az mbrc:GenderPolicies egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:genderPolicy πρέπει να είναι μία έννοια του mbrc:GenderPolicies, ή αντιστοιχισμένη σε αυτό. | mbr:genderPolicy moet één concept in mbrc:GenderPolicies zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:admissionMode ; sh:class skos:Concept ;
                  sh:node mbrsh:AdmissionModeValue ;
                  sh:message "mbr:admissionMode must be a concept in mbrc:AdmissionModes, or one mapped to it. | mbr:admissionMode ska vara ett begrepp i mbrc:AdmissionModes, eller ett som är mappat dit. | mbr:admissionMode doit être un concept de mbrc:AdmissionModes, ou un concept qui y est mappé. | mbr:admissionMode muss ein Konzept aus mbrc:AdmissionModes sein oder eines, das darauf abgebildet ist. | mbr:admissionMode deve essere un concetto di mbrc:AdmissionModes, o uno associato a esso. | mbr:admissionMode debe ser un concepto de mbrc:AdmissionModes, o uno asociado a él. | mbr:admissionMode tem de ser um conceito de mbrc:AdmissionModes, ou um associado a ele. | Az mbr:admissionMode értéke az mbrc:AdmissionModes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:admissionMode πρέπει να είναι έννοια του mbrc:AdmissionModes, ή αντιστοιχισμένη σε αυτό. | mbr:admissionMode moet een concept in mbrc:AdmissionModes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:ownershipModel ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:OwnershipModelValue ;
                  sh:message "mbr:ownershipModel must be one concept in mbrc:OwnershipModels, or one mapped to it. | mbr:ownershipModel ska vara ett begrepp i mbrc:OwnershipModels, eller ett som är mappat dit. | mbr:ownershipModel doit être un seul concept de mbrc:OwnershipModels, ou un concept qui y est mappé. | mbr:ownershipModel muss ein einzelnes Konzept aus mbrc:OwnershipModels sein oder eines, das darauf abgebildet ist. | mbr:ownershipModel deve essere un unico concetto di mbrc:OwnershipModels, o uno associato a esso. | mbr:ownershipModel debe ser un concepto de mbrc:OwnershipModels, o uno asociado a él. | mbr:ownershipModel tem de ser um conceito de mbrc:OwnershipModels, ou um associado a ele. | Az mbr:ownershipModel értéke az mbrc:OwnershipModels egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:ownershipModel πρέπει να είναι μία έννοια του mbrc:OwnershipModels, ή αντιστοιχισμένη σε αυτό. | mbr:ownershipModel moet één concept in mbrc:OwnershipModels zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:organizationStatus ; sh:maxCount 1 ; sh:class skos:Concept ;
                  sh:node mbrsh:OrganizationStatusValue ;
                  sh:message "mbr:organizationStatus must be one concept in mbrc:OrganizationStatuses, or one mapped to it. | mbr:organizationStatus ska vara ett begrepp i mbrc:OrganizationStatuses, eller ett som är mappat dit. | mbr:organizationStatus doit être un seul concept de mbrc:OrganizationStatuses, ou un concept qui y est mappé. | mbr:organizationStatus muss ein einzelnes Konzept aus mbrc:OrganizationStatuses sein oder eines, das darauf abgebildet ist. | mbr:organizationStatus deve essere un unico concetto di mbrc:OrganizationStatuses, o uno associato a esso. | mbr:organizationStatus debe ser un concepto de mbrc:OrganizationStatuses, o uno asociado a él. | mbr:organizationStatus tem de ser um conceito de mbrc:OrganizationStatuses, ou um associado a ele. | Az mbr:organizationStatus értéke az mbrc:OrganizationStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:organizationStatus πρέπει να είναι μία έννοια του mbrc:OrganizationStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:organizationStatus moet één concept in mbrc:OrganizationStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:organizationType ; sh:class skos:Concept ;
                  sh:node mbrsh:OrganizationTypeValue ;
                  sh:message "mbr:organizationType must be a concept in mbrc:OrganizationTypes, or one mapped to it. | mbr:organizationType ska vara ett begrepp i mbrc:OrganizationTypes, eller ett som är mappat dit. | mbr:organizationType doit être un concept de mbrc:OrganizationTypes, ou un concept qui y est mappé. | mbr:organizationType muss ein Konzept aus mbrc:OrganizationTypes sein oder eines, das darauf abgebildet ist. | mbr:organizationType deve essere un concetto di mbrc:OrganizationTypes, o uno associato a esso. | mbr:organizationType debe ser un concepto de mbrc:OrganizationTypes, o uno asociado a él. | mbr:organizationType tem de ser um conceito de mbrc:OrganizationTypes, ou um associado a ele. | Az mbr:organizationType értéke az mbrc:OrganizationTypes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:organizationType πρέπει να είναι έννοια του mbrc:OrganizationTypes, ή αντιστοιχισμένη σε αυτό. | mbr:organizationType moet een concept in mbrc:OrganizationTypes zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:publicBenefitStatus ; sh:class skos:Concept ;
                  sh:node mbrsh:PublicBenefitStatusValue ;
                  sh:message "mbr:publicBenefitStatus must be a concept in mbrc:PublicBenefitStatuses, or one mapped to it. | mbr:publicBenefitStatus ska vara ett begrepp i mbrc:PublicBenefitStatuses, eller ett som är mappat dit. | mbr:publicBenefitStatus doit être un concept de mbrc:PublicBenefitStatuses, ou un concept qui y est associé. | mbr:publicBenefitStatus muss ein Konzept aus mbrc:PublicBenefitStatuses sein oder eines, das darauf abgebildet ist. | mbr:publicBenefitStatus deve essere un concetto di mbrc:PublicBenefitStatuses, o uno associato a esso. | mbr:publicBenefitStatus debe ser un concepto de mbrc:PublicBenefitStatuses, o uno asociado a él. | mbr:publicBenefitStatus tem de ser um conceito de mbrc:PublicBenefitStatuses, ou um associado a ele. | Az mbr:publicBenefitStatus értéke az mbrc:PublicBenefitStatuses egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:publicBenefitStatus πρέπει να είναι έννοια του mbrc:PublicBenefitStatuses, ή αντιστοιχισμένη σε αυτό. | mbr:publicBenefitStatus moet een concept in mbrc:PublicBenefitStatuses zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:legalForm ; sh:class skos:Concept ;
                  sh:node mbrsh:LegalFormValue ;
                  sh:message "mbr:legalForm must be a concept in mbrc:LegalForms, or one mapped to it. | mbr:legalForm ska vara ett begrepp i mbrc:LegalForms, eller ett som är mappat dit. | mbr:legalForm doit être un concept de mbrc:LegalForms, ou un concept qui y est mappé. | mbr:legalForm muss ein Konzept aus mbrc:LegalForms sein oder eines, das darauf abgebildet ist. | mbr:legalForm deve essere un concetto di mbrc:LegalForms, o uno associato a esso. | mbr:legalForm debe ser un concepto de mbrc:LegalForms, o uno asociado a él. | mbr:legalForm tem de ser um conceito de mbrc:LegalForms, ou um associado a ele. | Az mbr:legalForm értéke az mbrc:LegalForms egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:legalForm πρέπει να είναι έννοια του mbrc:LegalForms, ή αντιστοιχισμένη σε αυτό. | mbr:legalForm moet een concept in mbrc:LegalForms zijn, of een concept dat daarop is afgebeeld." ] ,
                [ sh:path mbr:startDate ; sh:minCount 1 ; sh:severity sh:Warning ;
                  sh:message "Give the date from which the period applies (mbr:startDate). | Ange från vilket datum perioden gäller (mbr:startDate). | Indiquez la date à partir de laquelle la période s'applique (mbr:startDate). | Das Datum angeben, ab dem der Zeitraum gilt (mbr:startDate). | Indicare la data da cui si applica il periodo (mbr:startDate). | Indique la fecha desde la que se aplica el período (mbr:startDate). | Indique a data a partir da qual se aplica o período (mbr:startDate). | Adja meg a dátumot, amelytől az időszak érvényes (mbr:startDate). | Δώστε την ημερομηνία από την οποία ισχύει η περίοδος (mbr:startDate). | Geef de datum vanaf wanneer de periode geldt (mbr:startDate)." ] ;

    # One organisation cannot have two different values of the same single-valued property
    # at once. Reported only when two periods certainly overlap: both have a start and an end,
    # and the latest each could start is before the earliest the other could end (dates
    # compared as in mbrsh:EndDateShape). A period that ends on the day another starts, or
    # that has no end date, is not reported. mbr:admissionMode, mbr:organizationType,
    # mbr:legalForm and mbr:publicBenefitStatus are left out: an organisation may admit in
    # several ways, have several types, in some jurisdictions more than one legal form at
    # once, and several public-benefit statuses (an Italian association is both a
    # Third Sector entity and a social promotion association).
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "The organisation has two different values of {?p} in periods that certainly overlap ({?other}). | Organisationen har två olika värden på {?p} i perioder som säkert överlappar ({?other}). | L'organisation a deux valeurs différentes de {?p} dans des périodes qui se chevauchent certainement ({?other}). | Die Organisation hat zwei verschiedene Werte von {?p} in Zeiträumen, die sich sicher überschneiden ({?other}). | L'organizzazione ha due valori diversi di {?p} in periodi che certamente si sovrappongono ({?other}). | La organización tiene dos valores distintos de {?p} en períodos que con seguridad se solapan ({?other}). | A organização tem dois valores diferentes de {?p} em períodos que com certeza se sobrepõem ({?other}). | A szervezetnek két különböző értéke van a(z) {?p} tulajdonságból biztosan átfedő időszakokban ({?other}). | Η οργάνωση έχει δύο διαφορετικές τιμές του {?p} σε περιόδους που σίγουρα επικαλύπτονται ({?other}). | De organisatie heeft twee verschillende waarden van {?p} in perioden die elkaar zeker overlappen ({?other})." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT $this ?other ?p WHERE {
                ?org mbr:hasPeriod $this , ?other .
                FILTER (?other != $this)
                VALUES ?p { mbr:genderPolicy mbr:ownershipModel mbr:organizationStatus }
                $this ?p ?v1 ; mbr:startDate ?s1 ; mbr:endDate ?e1 .
                ?other ?p ?v2 ; mbr:startDate ?s2 ; mbr:endDate ?e2 .
                FILTER (?v1 != ?v2)
                FILTER (datatype(?s1) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                        datatype(?e1) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                        datatype(?s2) IN (xsd:date, xsd:gYearMonth, xsd:gYear) &&
                        datatype(?e2) IN (xsd:date, xsd:gYearMonth, xsd:gYear))
                FILTER (REGEX(STR(?s1), "^[0-9]{4}") && REGEX(STR(?e1), "^[0-9]{4}") &&
                        REGEX(STR(?s2), "^[0-9]{4}") && REGEX(STR(?e2), "^[0-9]{4}"))
                BIND (IF(datatype(?s1) = xsd:date, SUBSTR(STR(?s1), 1, 10),
                      IF(datatype(?s1) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?s1), 1, 7), "-31"),
                         CONCAT(SUBSTR(STR(?s1), 1, 4), "-12-31"))) AS ?latestStart1)
                BIND (IF(datatype(?s2) = xsd:date, SUBSTR(STR(?s2), 1, 10),
                      IF(datatype(?s2) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?s2), 1, 7), "-31"),
                         CONCAT(SUBSTR(STR(?s2), 1, 4), "-12-31"))) AS ?latestStart2)
                BIND (IF(datatype(?e1) = xsd:date, SUBSTR(STR(?e1), 1, 10),
                      IF(datatype(?e1) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?e1), 1, 7), "-01"),
                         CONCAT(SUBSTR(STR(?e1), 1, 4), "-01-01"))) AS ?earliestEnd1)
                BIND (IF(datatype(?e2) = xsd:date, SUBSTR(STR(?e2), 1, 10),
                      IF(datatype(?e2) = xsd:gYearMonth, CONCAT(SUBSTR(STR(?e2), 1, 7), "-01"),
                         CONCAT(SUBSTR(STR(?e2), 1, 4), "-01-01"))) AS ?earliestEnd2)
                FILTER (?latestStart1 < ?earliestEnd2 && ?latestStart2 < ?earliestEnd1)
            }
        """
    ] .

##############################################################################
# Registry identifiers (rov:registration)
##############################################################################

mbrsh:IdentifierShape a sh:NodeShape ;
    sh:targetClass adms:Identifier ;
    sh:property [ sh:path skos:notation ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:message "A registry identifier needs exactly one skos:notation, the number itself. | En registeridentifierare behöver exakt en skos:notation, själva numret. | Un identifiant de registre a besoin d'exactement une skos:notation, le numéro lui-même. | Eine Registerkennung braucht genau eine skos:notation, die Nummer selbst. | Un identificativo di registro richiede esattamente una skos:notation, il numero stesso. | Un identificador de registro necesita exactamente una skos:notation, el número mismo. | Um identificador de registo precisa de exatamente uma skos:notation, o próprio número. | A nyilvántartási azonosítónak pontosan egy skos:notation értéke kell legyen, maga a szám. | Ένα αναγνωριστικό μητρώου χρειάζεται ακριβώς ένα skos:notation, τον ίδιο τον αριθμό. | Een registeridentificatie heeft precies één skos:notation nodig, het nummer zelf." ] ,
                [ sh:path adms:schemaAgency ; sh:minCount 1 ; sh:datatype xsd:string ;
                  sh:severity sh:Warning ;
                  sh:message "Name the register that issued the identifier with adms:schemaAgency. | Ange registret som utfärdat identifieraren med adms:schemaAgency. | Nommer le registre qui a délivré l'identifiant avec adms:schemaAgency. | Das Register, das die Kennung vergeben hat, mit adms:schemaAgency benennen. | Indicare il registro che ha rilasciato l'identificativo con adms:schemaAgency. | Indique el registro que expidió el identificador con adms:schemaAgency. | Indique o registo que emitiu o identificador com adms:schemaAgency. | Nevezze meg az azonosítót kiállító nyilvántartást az adms:schemaAgency-vel. | Ονομάστε το μητρώο που εξέδωσε το αναγνωριστικό με το adms:schemaAgency. | Noem het register dat de identificatie heeft uitgegeven met adms:schemaAgency." ] .

##############################################################################
# Premises, addresses, coordinates, occupancy and member counts
##############################################################################

mbrsh:PremisesShape a sh:NodeShape ;
    sh:targetClass mbr:Premises ;
    sh:property [ sh:path schema:address ; sh:class schema:PostalAddress ] ,
                [ sh:path schema:geo ; sh:maxCount 1 ; sh:class schema:GeoCoordinates ] ,
                [ sh:path schema:containedInPlace ; sh:nodeKind sh:IRI ] ,
                [ sh:path mbr:dressCode ; sh:class skos:Concept ; sh:node mbrsh:DressCodeValue ;
                  sh:message "mbr:dressCode must be a concept in mbrc:DressCodes, or one mapped to it. | mbr:dressCode ska vara ett begrepp i mbrc:DressCodes, eller ett som är mappat dit. | mbr:dressCode doit être un concept de mbrc:DressCodes, ou un concept qui y est mappé. | mbr:dressCode muss ein Konzept aus mbrc:DressCodes sein oder eines, das darauf abgebildet ist. | mbr:dressCode deve essere un concetto di mbrc:DressCodes, o uno associato a esso. | mbr:dressCode debe ser un concepto de mbrc:DressCodes, o uno asociado a él. | mbr:dressCode tem de ser um conceito de mbrc:DressCodes, ou um associado a ele. | Az mbr:dressCode értéke az mbrc:DressCodes egy fogalma, vagy egy hozzárendelt fogalom kell legyen. | Το mbr:dressCode πρέπει να είναι έννοια του mbrc:DressCodes, ή αντιστοιχισμένη σε αυτό. | mbr:dressCode moet een concept in mbrc:DressCodes zijn, of een concept dat daarop is afgebeeld." ] ;
    # A building may have had several addresses over time, but only one current one.
    sh:sparql [
        a sh:SPARQLConstraint ;
        sh:message "Premises have more than one current address (addresses without mbr:endDate). Give former addresses an end date. | Lokalen har mer än en nuvarande adress (adresser utan mbr:endDate). Ge tidigare adresser ett slutdatum. | Les locaux ont plus d'une adresse actuelle (adresses sans mbr:endDate). Donner une date de fin aux anciennes adresses. | Die Räumlichkeiten haben mehr als eine aktuelle Adresse (Adressen ohne mbr:endDate). Früheren Adressen ein Enddatum geben. | I locali hanno più di un indirizzo attuale (indirizzi senza mbr:endDate). Dare una data di fine agli indirizzi precedenti. | Los locales tienen más de una dirección actual (direcciones sin mbr:endDate). Dé una fecha de fin a las direcciones anteriores. | As instalações têm mais de uma morada atual (moradas sem mbr:endDate). Dê data de fim às moradas anteriores. | A helyiségeknek egynél több jelenlegi címük van (mbr:endDate nélküli címek). Adjon záró dátumot a korábbi címeknek. | Οι χώροι έχουν περισσότερες από μία τρέχουσες διευθύνσεις (διευθύνσεις χωρίς mbr:endDate). Δώστε ημερομηνία λήξης στις παλιές διευθύνσεις. | Het onderkomen heeft meer dan één huidig adres (adressen zonder mbr:endDate). Geef eerdere adressen een einddatum." ;
        sh:prefixes <https://w3id.org/membership/shapes> ;
        sh:select """
            SELECT DISTINCT $this WHERE {
                $this schema:address ?a1 , ?a2 .
                FILTER (?a1 != ?a2)
                FILTER NOT EXISTS { ?a1 mbr:endDate ?e1 }
                FILTER NOT EXISTS { ?a2 mbr:endDate ?e2 }
            }
        """
    ] .

mbrsh:PostalAddressShape a sh:NodeShape ;
    sh:targetClass schema:PostalAddress ;
    sh:property [ sh:path schema:streetAddress ; sh:maxCount 1 ; sh:datatype xsd:string ] ,
                [ sh:path schema:postalCode ; sh:maxCount 1 ; sh:datatype xsd:string ] ,
                [ sh:path schema:addressRegion ; sh:maxCount 1 ; sh:datatype xsd:string ] ,
                [ sh:path schema:addressLocality ; sh:minCount 1 ; sh:maxCount 1 ; sh:datatype xsd:string ;
                  sh:severity sh:Warning ] ,
                [ sh:path schema:addressCountry ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:datatype xsd:string ; sh:pattern "^[A-Z]{2}$" ;
                  sh:message "schema:addressCountry must be a two-letter ISO 3166-1 code such as GB or SE. | schema:addressCountry ska vara en tvåbokstavskod enligt ISO 3166-1, t.ex. GB eller SE. | schema:addressCountry doit être un code ISO 3166-1 de deux lettres, comme GB ou SE. | schema:addressCountry muss ein zweibuchstabiger ISO-3166-1-Code wie GB oder SE sein. | schema:addressCountry deve essere un codice ISO 3166-1 di due lettere come GB o SE. | schema:addressCountry debe ser un código ISO 3166-1 de dos letras como GB o SE. | schema:addressCountry tem de ser um código ISO 3166-1 de duas letras como GB ou SE. | A schema:addressCountry értéke kétbetűs ISO 3166-1 kód kell legyen, például GB vagy SE. | Το schema:addressCountry πρέπει να είναι διγράμματος κωδικός ISO 3166-1 όπως GB ή SE. | schema:addressCountry moet een ISO 3166-1-code van twee letters zijn, zoals GB of SE." ] .

mbrsh:CoordinateList
    sh:or ( [ sh:datatype xsd:decimal ] [ sh:datatype xsd:double ] ) .

mbrsh:GeoCoordinatesShape a sh:NodeShape ;
    sh:targetClass schema:GeoCoordinates ;
    sh:property [ sh:path schema:latitude ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:node mbrsh:CoordinateList ; sh:minInclusive -90 ; sh:maxInclusive 90 ;
                  sh:message "schema:latitude must be one decimal number between -90 and 90. | schema:latitude ska vara ett decimaltal mellan -90 och 90. | schema:latitude doit être un seul nombre décimal compris entre -90 et 90. | schema:latitude muss eine einzelne Dezimalzahl zwischen -90 und 90 sein. | schema:latitude deve essere un unico numero decimale compreso tra -90 e 90. | schema:latitude debe ser un único número decimal entre -90 y 90. | schema:latitude tem de ser um único número decimal entre -90 e 90. | A schema:latitude értéke egyetlen tizedes szám kell legyen -90 és 90 között. | Το schema:latitude πρέπει να είναι ένας δεκαδικός αριθμός μεταξύ -90 και 90. | schema:latitude moet één decimaal getal tussen -90 en 90 zijn." ] ,
                [ sh:path schema:longitude ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:node mbrsh:CoordinateList ; sh:minInclusive -180 ; sh:maxInclusive 180 ;
                  sh:message "schema:longitude must be one decimal number between -180 and 180. | schema:longitude ska vara ett decimaltal mellan -180 och 180. | schema:longitude doit être un seul nombre décimal compris entre -180 et 180. | schema:longitude muss eine einzelne Dezimalzahl zwischen -180 und 180 sein. | schema:longitude deve essere un unico numero decimale compreso tra -180 e 180. | schema:longitude debe ser un único número decimal entre -180 y 180. | schema:longitude tem de ser um único número decimal entre -180 e 180. | A schema:longitude értéke egyetlen tizedes szám kell legyen -180 és 180 között. | Το schema:longitude πρέπει να είναι ένας δεκαδικός αριθμός μεταξύ -180 και 180. | schema:longitude moet één decimaal getal tussen -180 en 180 zijn." ] .

mbrsh:OccupancyShape a sh:NodeShape ;
    sh:targetClass mbr:Occupancy ;
    sh:property [ sh:path mbr:occupant ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Organization ] ,
                [ sh:path mbr:occupiedPremises ; sh:minCount 1 ; sh:maxCount 1 ; sh:class org:Site ] .

# xsd:nonNegativeInteger, as in the OWL range. A plain Turtle 42 is an xsd:integer with
# the same value, which the OWL range also admits, so it passes when it is zero or more.
mbrsh:CountList
    sh:or ( [ sh:datatype xsd:nonNegativeInteger ] [ sh:datatype xsd:integer ; sh:minInclusive 0 ] ) .

mbrsh:MemberCountShape a sh:NodeShape ;
    sh:targetClass mbr:MemberCount ;
    sh:property [ sh:path mbr:count ; sh:minCount 1 ; sh:maxCount 1 ;
                  sh:node mbrsh:CountList ;
                  sh:message "mbr:count must be one non-negative integer (xsd:nonNegativeInteger, or xsd:integer of zero or more). | mbr:count ska vara ett enda icke-negativt heltal (xsd:nonNegativeInteger, eller xsd:integer som är noll eller större). | mbr:count doit être un seul entier non négatif (xsd:nonNegativeInteger, ou xsd:integer égal ou supérieur à zéro). | mbr:count muss eine einzelne nichtnegative ganze Zahl sein (xsd:nonNegativeInteger oder xsd:integer von null oder mehr). | mbr:count deve essere un unico numero intero non negativo (xsd:nonNegativeInteger, o xsd:integer pari o superiore a zero). | mbr:count debe ser un único entero no negativo (xsd:nonNegativeInteger, o xsd:integer igual o mayor que cero). | mbr:count tem de ser um único inteiro não negativo (xsd:nonNegativeInteger, ou xsd:integer igual ou superior a zero). | Az mbr:count értéke egyetlen nemnegatív egész szám kell legyen (xsd:nonNegativeInteger, vagy nullánál nem kisebb xsd:integer). | Το mbr:count πρέπει να είναι ένας μη αρνητικός ακέραιος (xsd:nonNegativeInteger, ή xsd:integer μηδέν ή μεγαλύτερο). | mbr:count moet één niet-negatief geheel getal zijn (xsd:nonNegativeInteger, of xsd:integer van nul of meer)." ] ,
                [ sh:path mbr:asOf ; sh:minCount 1 ;
                  sh:message "A member count needs the date it refers to (mbr:asOf). | Ett medlemsantal behöver det datum det avser (mbr:asOf). | Un effectif a besoin de la date à laquelle il se rapporte (mbr:asOf). | Eine Mitgliederzahl braucht das Datum, auf das sie sich bezieht (mbr:asOf). | Un numero di soci richiede la data a cui si riferisce (mbr:asOf). | Un recuento de miembros necesita la fecha a la que se refiere (mbr:asOf). | Uma contagem de membros precisa da data a que se refere (mbr:asOf). | A taglétszámnak szüksége van arra a dátumra, amelyre vonatkozik (mbr:asOf). | Ένας αριθμός μελών χρειάζεται την ημερομηνία στην οποία αναφέρεται (mbr:asOf). | Een ledental heeft de datum nodig waarop het betrekking heeft (mbr:asOf)." ] .

mbrsh:ConceptShape a sh:NodeShape ;
    sh:targetClass skos:Concept ;
    sh:property [ sh:path skos:prefLabel ; sh:minCount 1 ; sh:uniqueLang true ;
                  sh:severity sh:Warning ] .
