- From: Martynas Jusevičius <martynas@atomgraph.com>
- Date: Tue, 17 Sep 2019 13:57:13 +0200
- To: Mikael Pesonen <mikael.pesonen@lingsoft.fi>
- Cc: public-declarative-apps@w3.org
Hi Mikael, the template URI on its own is irrelevant here, it could be a blank node resource. It becomes important when one intends to reuse templates, e.g. extend them or reference them, possibly from another LDT ontology. Yes it is the ldt:match that holds the URI template that request URI is matched against. I have expanded the explanation here: https://github.com/AtomGraph/Processor/wiki/Linked-Data-Templates#templates As for the agent ID, one option to pass a value to the LDT template is using template parameters: https://github.com/AtomGraph/Processor/wiki/Linked-Data-Templates#parameters Then if a request URI is https://resource.lingsoft.fi/286c384d-cd5c-4887-9b85-94c0c147f709?agent=123456, a variable binding (?agent, "123456") is applied to the query string from ldt:query, before it is executed. This might or might not work for your use case. Martynas On Tue, Sep 17, 2019 at 1:43 PM Mikael Pesonen <mikael.pesonen@lingsoft.fi> wrote: > > > Hmm, still mixing up things. So ldt:match has to match the resource URI. > > On 17/09/2019 12:13, Mikael Pesonen wrote: > > > > Ok now I got it, the template address has to be the same as resource URI. > > Just one question, in our case, https://base/{uuid}, how should we > > forward the agent id (access level) to the template for utilizing ACL? > > > > > > > > On 17/09/2019 11:40, Martynas Jusevičius wrote: > >> Thanks Mikael, > >> > >> the example makes it clearer. > >> > >> So the URI template for all persons (and I guess all resources in > >> general?) is "/{uuid}", if we take https://resource.lingsoft.fi as the > >> base URI. Which means that you could not match two different LDT > >> templates for different types of persons. > >> > >> Then my suggestion with using a single template with a query that > >> references the ACL graph still stands. Let me know if you need help > >> setting it up in Processor. > >> > >> Martynas > >> > >> On Mon, Sep 16, 2019 at 11:27 AM Mikael Pesonen > >> <mikael.pesonen@lingsoft.fi> wrote: > >>> > >>> Here is a sample data: > >>> > >>> <https://resource.lingsoft.fi/286c384d-cd5c-4887-9b85-94c0c147f709> > >>> a foaf:Person ; > >>> vcard:family-name "Pesonen" ; > >>> vcard:fn "Mikael Pesonen" ; > >>> vcard:given-name "Mikael" ; > >>> vcard:hasEmail > >>> <https://resource.lingsoft.fi/cf9b02b7-bd0d-486e-b0d9-da1464e27d2e> , > >>> <https://resource.lingsoft.fi/5c04aa23-6c42-44a1-9ac9-69ee255ac170> ; > >>> vcard:hasGender vcard:Male ; > >>> vcard:hasInstantMessage > >>> <https://resource.lingsoft.fi/4aa01d37-744c-4964-a794-d997aa376584> ; > >>> vcard:hasPhoto > >>> <https://resource.lingsoft.fi/8f4a4ddd-43c2-4e27-8ed7-996dd00e939c> ; > >>> vcard:hasTelephone > >>> <https://resource.lingsoft.fi/3755ed0c-81b7-430e-92a0-16fc80ba41b4> ; > >>> org:basedAt > >>> <https://resource.lingsoft.fi/b48a0820-6921-43fc-a346-e72397265bbe> ; > >>> org:memberOf > >>> <https://resource.lingsoft.fi/810dfbff-e6fb-458a-b27d-3726a27e5109> ; > >>> foaf:account > >>> <https://resource.lingsoft.fi/2f0aa772-f845-4f43-b607-dc65ff66b9aa> ; > >>> <https://resource.lingsoft.fi/cf9b02b7-bd0d-486e-b0d9-da1464e27d2e> > >>> a vcard:Email , vcard:Work ; > >>> rdfs:label "***@lingsoft.fi" ; > >>> vcard:hasValue <mailto:***@lingsoft.fi> . > >>> > >>> > >>> So most of the person's values are resources and every resource has id > >>> of type https://resource.lingsoft.fi/<UUID>. > >>> > >>> > >>> Mikael > >>> > >>> > >>> On 15/09/2019 01:02, Martynas Jusevičius wrote: > >>>> I meant the first and the ACL examples as alternatives, but yes you > >>>> can combine the approaches as well. Again, depends mostly on your URIs > >>>> - and are able to change their pattern? > >>>> > >>>> I think it would help if you could show some RDF data that represents > >>>> your case (does not have to be the actual person data :)) Either paste > >>>> inline or as a Gist if it's larger. > >>>> > >>>> Re. ACL, we use a filter in our LinkedDataHub platform that checks ACL > >>>> access before the actual LDT request is invoked. And if query results > >>>> need to depend on the access level, we reference the ACL dataset as I > >>>> showed in the example. > >>>> > >>>> Martynas > >>>> > >>>> On Fri, Sep 13, 2019 at 3:55 PM Mikael Pesonen > >>>> <mikael.pesonen@lingsoft.fi> wrote: > >>>>> Looking at your first example, looks like that and this acl > >>>>> version work > >>>>> both? > >>>>> > >>>>> So as with your first example: > >>>>> > >>>>> /person/basic_access/{id} > >>>>> -- > >>>>> > >>>>> :BasicPersonAccessItem a ldt:Template ; > >>>>> ldt:match "/person/basic_access/{id}" ; > >>>>> ldt:query :ConstructBasicPerson ; > >>>>> > >>>>> ---- > >>>>> /person/admin_access/{id} > >>>>> -- > >>>>> :AdminPersonAccessItem a ldt:Template ; > >>>>> ldt:match "/person/admin_access/{id}" ; > >>>>> ldt:query :ConstructFullPerson ; > >>>>> > >>>>> > >>>>> > >>>>> And this acl example > >>>>> > >>>>> /person/{agent}/{id} > >>>>> -- > >>>>> :PersonAccessItem a ldt:Template ; > >>>>> ldt:match "/person/{agent}/{id}" ; > >>>>> ldt:query :ConstructPerson ; > >>>>> ... > >>>>> > >>>>> > >>>>> ACL example sure is more refined since you can define the access > >>>>> levels > >>>>> in the ACL data. > >>>>> > >>>>> > >>>>> On 13/09/2019 16:25, Martynas Jusevičius wrote: > >>>>>> Well if you only have one kind of person resources with a single URI > >>>>>> pattern, then you cannot select (match) different LDT templates. > >>>>>> That is because an LDT template maps one URI pattern to one SPARQL > >>>>>> command. The matching process is not looking into the SPARQL query > >>>>>> results at all, only at the request URI and the application's LDT > >>>>>> ontology. > >>>>>> > >>>>>> I think you can solve this with a single query though. What we do is > >>>>>> provide the URI of the requesting agent as a query binding, e.g. > >>>>>> ?agent variable. Something like > >>>>>> > >>>>>> :ConstructPerson a sp:Construct ; > >>>>>> sp:text """ > >>>>>> PREFIX foaf: <http://xmlns.com/foaf/0.1/> > >>>>>> PREFIX acl: <http://www.w3.org/ns/auth/acl#> > >>>>>> > >>>>>> CONSTRUCT > >>>>>> { > >>>>>> ?this a foaf:Person . > >>>>>> ?this foaf:name ?name . > >>>>>> ?this ?p ?o . > >>>>>> } > >>>>>> WHERE > >>>>>> { { ?this a foaf:Person ; > >>>>>> foaf:name ?name > >>>>>> } > >>>>>> UNION > >>>>>> { GRAPH <acl> > >>>>>> { ?auth acl:accessTo ?this ; > >>>>>> acl:agent ?agent . > >>>>>> } > >>>>>> ?this ?p ?o > >>>>>> } > >>>>>> } > >>>>>> """ ; > >>>>>> rdfs:isDefinedBy : . > >>>>>> > >>>>>> The idea is that the person query always returns "basic" properties, > >>>>>> and adds all properties *only* if the agent ?agent has an > >>>>>> authorization to access the requested resource ?this. > >>>>>> This approach requires that the query has access to the ACL data, > >>>>>> which I have indicated here as GRAPH <acl>. The actual pattern for > >>>>>> authorization check will probably be more complex of course. > >>>>>> It also requires that the authentication mechanism can provide > >>>>>> the URI > >>>>>> of the agent. > >>>>>> > >>>>>> I hope I got what you meant :) > >>>>>> > >>>>>> On Fri, Sep 13, 2019 at 2:58 PM Mikael Pesonen > >>>>>> <mikael.pesonen@lingsoft.fi> wrote: > >>>>>>> Ah, I might have explained our case bit vaguely. So I just meant > >>>>>>> that we > >>>>>>> have in RDF data one kind of person resources, and > >>>>>>> depending on the access rights in the application, you are > >>>>>>> allowed to > >>>>>>> see different portions of that person's data. > >>>>>>> Basic user sees only the name, for example, and admin user is > >>>>>>> allowed to > >>>>>>> see all data. This is handled by selecting different template > >>>>>>> for basic > >>>>>>> user and admin, right? > >>>>>>> > >>>>>>> > >>>>>>> > >>>>>>> On 13/09/2019 15:52, Martynas Jusevičius wrote: > >>>>>>>> Mikael, > >>>>>>>> > >>>>>>>> this is related to hierarchical URIs: > >>>>>>>> http://patterns.dataincubator.org/book/hierarchical-uris.html > >>>>>>>> > >>>>>>>> In your case, the question is how you have organized the > >>>>>>>> collections/items of basic and admin persons in your dataset. > >>>>>>>> > >>>>>>>> One option is that both "basic persons" and "admin persons" > >>>>>>>> belong to > >>>>>>>> the same collection and have a single URI pattern: /persons/{id} > >>>>>>>> In this case you cannot tell if resource /persons/12345 is a > >>>>>>>> "basic > >>>>>>>> person" or "admin person" just from its URI. You need to > >>>>>>>> dereference > >>>>>>>> it and the look into RDF types and properties. > >>>>>>>> > >>>>>>>> Another option is that you treat them as belonging to separate > >>>>>>>> collections, for example: /persons/{id} and /admins/{id} > >>>>>>>> In this case you can easily tell if a resource is a "basic > >>>>>>>> person" or > >>>>>>>> an "admin person" already from its URIs. > >>>>>>>> > >>>>>>>> Linked Data Templates are best suited for this second case, > >>>>>>>> where URI > >>>>>>>> space is subdivided into hierarchies based on entity types. > >>>>>>>> That makes > >>>>>>>> it easy to define URI templates that match precisely the set of > >>>>>>>> resources that you want. > >>>>>>>> > >>>>>>>> Does it make it clearer? > >>>>>>>> > >>>>>>>> On Fri, Sep 13, 2019 at 2:08 PM Mikael Pesonen > >>>>>>>> <mikael.pesonen@lingsoft.fi> wrote: > >>>>>>>>> Hi Martynas, > >>>>>>>>> > >>>>>>>>> thank you for the examples, GET seems clear now. > >>>>>>>>> > >>>>>>>>> Good point about the person / document. We probably end up > >>>>>>>>> with three > >>>>>>>>> kind of resources: actual object, admin record (who last > >>>>>>>>> modified etc), > >>>>>>>>> and web page or another document about the object. > >>>>>>>>> > >>>>>>>>> Just one question: what did you mean by > >>>>>>>>> > >>>>>>>>> "If you cannot distinguish "basic person" from "admin person" > >>>>>>>>> by their > >>>>>>>>> URIs"? > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> We are not quite there yet with updates, so we might have > >>>>>>>>> questions > >>>>>>>>> later about those. > >>>>>>>>> > >>>>>>>>> Br, > >>>>>>>>> Mikael > >>>>>>>>> > >>>>>>>>> On 11/09/2019 18:45, Martynas Jusevičius wrote: > >>>>>>>>>> Hi Mikael, > >>>>>>>>>> > >>>>>>>>>> thanks for reaching out. > >>>>>>>>>> > >>>>>>>>>> There is more information on LDT in the AtomGraph Processor > >>>>>>>>>> wiki, more > >>>>>>>>>> specifically: > >>>>>>>>>> https://github.com/AtomGraph/Processor/wiki/Linked-Data-Templates > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> The matching is based on URIs: relative request URI is being > >>>>>>>>>> matched > >>>>>>>>>> against the ldt:match values of templates in the ontology. > >>>>>>>>>> > >>>>>>>>>> Then, from the matching template (if there is any), the > >>>>>>>>>> SPARQL command > >>>>>>>>>> is retrieved using either ldt:query or ldt:update (depending > >>>>>>>>>> on the > >>>>>>>>>> HTTP request method). > >>>>>>>>>> > >>>>>>>>>> To address your example, templates and queries could look > >>>>>>>>>> like this: > >>>>>>>>>> > >>>>>>>>>> :BasicPersonItem a ldt:Template ; > >>>>>>>>>> ldt:match "/person/basic/{id}" ; > >>>>>>>>>> ldt:query :ConstructBasicPerson ; > >>>>>>>>>> rdfs:isDefinedBy : . > >>>>>>>>>> > >>>>>>>>>> :ConstructBasicPerson a sp:Construct ; > >>>>>>>>>> sp:text """ > >>>>>>>>>> PREFIX foaf: <http://xmlns.com/foaf/0.1/> > >>>>>>>>>> > >>>>>>>>>> CONSTRUCT > >>>>>>>>>> { > >>>>>>>>>> ?this a foaf:Person ; > >>>>>>>>>> foaf:name ?name . > >>>>>>>>>> } > >>>>>>>>>> { > >>>>>>>>>> ?this a foaf:Person ; > >>>>>>>>>> foaf:name ?name . > >>>>>>>>>> } > >>>>>>>>>> """ ; > >>>>>>>>>> rdfs:isDefinedBy : . > >>>>>>>>>> > >>>>>>>>>> :AdminPersonItem a ldt:Template ; > >>>>>>>>>> ldt:match "/person/admin/{id}" ; > >>>>>>>>>> ldt:query :ConstructAdminPerson ; > >>>>>>>>>> rdfs:isDefinedBy : . > >>>>>>>>>> > >>>>>>>>>> :ConstructAdminPerson a sp:Construct ; > >>>>>>>>>> sp:text """ > >>>>>>>>>> CONSTRUCT WHERE > >>>>>>>>>> { > >>>>>>>>>> ?this ?p ?o > >>>>>>>>>> } > >>>>>>>>>> """ ; > >>>>>>>>>> rdfs:isDefinedBy : . > >>>>>>>>>> > >>>>>>>>>> "Basic person" query retrieves only name and type, "admin > >>>>>>>>>> person" > >>>>>>>>>> query retrieves all properties. > >>>>>>>>>> This example requires that basic and admin person resources > >>>>>>>>>> can be > >>>>>>>>>> differentiated by their URIs, i.e. "/person/basic/{id}" vs > >>>>>>>>>> "/person/admin/{id}". > >>>>>>>>>> > >>>>>>>>>> It also assumes that persons are documents (since they can be > >>>>>>>>>> dereferenced over HTTP), which is not kosher re. httpRange-14 > >>>>>>>>>> [1]. A > >>>>>>>>>> better solution would have separate resources for persons > >>>>>>>>>> e.g. using > >>>>>>>>>> hash URIs such as #this) and explicitly connect them to > >>>>>>>>>> documents > >>>>>>>>>> using an RDF property. We use > >>>>>>>>>> foaf:primaryTopic/foaf:isPrimaryTopicOf. > >>>>>>>>>> But this is a whole topic on its own. > >>>>>>>>>> > >>>>>>>>>> If you cannot distinguish "basic person" from "admin person" > >>>>>>>>>> by their > >>>>>>>>>> URIs, you could also have a template that matches both and > >>>>>>>>>> maps to a > >>>>>>>>>> single query. The question is then whether you can > >>>>>>>>>> differentiate which > >>>>>>>>>> properties to return using a single query. > >>>>>>>>>> > >>>>>>>>>> Does this help? > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> [1] https://www.w3.org/2001/tag/group/track/issues/14 > >>>>>>>>>> > >>>>>>>>>> Martynas > >>>>>>>>>> atomgraph.com > >>>>>>>>>> > >>>>>>>>>> On Wed, Sep 11, 2019 at 11:21 AM Mikael Pesonen > >>>>>>>>>> <mikael.pesonen@lingsoft.fi> wrote: > >>>>>>>>>>> Hi Martynas, > >>>>>>>>>>> > >>>>>>>>>>> we have a proprietary implementation now: > >>>>>>>>>>> > >>>>>>>>>>> js/React app generates a custom json out of form data. That > >>>>>>>>>>> is sent > >>>>>>>>>>> (with a template id) to also custom proxy, which converts > >>>>>>>>>>> the json into > >>>>>>>>>>> SPARQL using pre made templates. SPARQL is then queried on > >>>>>>>>>>> Apache Jena. > >>>>>>>>>>> > >>>>>>>>>>> Now we would like to replace all custom bits with one ore > >>>>>>>>>>> more standards. > >>>>>>>>>>> > >>>>>>>>>>> Is it possible to have any kind of templates with LDT? For > >>>>>>>>>>> example > >>>>>>>>>>> "person_basic" and "person_admin", > >>>>>>>>>>> where admin contains more properties of a person? > >>>>>>>>>>> > >>>>>>>>>>> I'm still having trouble to understand how the SPARQL > >>>>>>>>>>> template is > >>>>>>>>>>> selected with LDT. > >>>>>>>>>>> > >>>>>>>>>>> Br, > >>>>>>>>>>> Mikael > >>>>>>>>>>> > >>>>>>>>>>> On 10/09/2019 15:50, Martynas Jusevičius wrote: > >>>>>>>>>>>> Hey Mikael, > >>>>>>>>>>>> > >>>>>>>>>>>> we have a simple example here: > >>>>>>>>>>>> https://github.com/AtomGraph/Processor#example > >>>>>>>>>>>> > >>>>>>>>>>>> Do you have some specific use case in mind? If you can > >>>>>>>>>>>> share it, I can > >>>>>>>>>>>> probably look into it. > >>>>>>>>>>>> > >>>>>>>>>>>> There is a Community Group for Linked Data Templates which > >>>>>>>>>>>> includes a > >>>>>>>>>>>> mailing list: https://www.w3.org/community/declarative-apps/ > >>>>>>>>>>>> > >>>>>>>>>>>> Martynas > >>>>>>>>>>>> atomgraph.com > >>>>>>>>>>>> > >>>>>>>>>>>> On Tue, Sep 10, 2019 at 1:27 PM Mikael Pesonen > >>>>>>>>>>>> <mikael.pesonen@lingsoft.fi> wrote: > >>>>>>>>>>>>> In the example there is the GET request > >>>>>>>>>>>>> > >>>>>>>>>>>>> GET > >>>>>>>>>>>>> /people/Berners-Lee?g=http%3A%2F%2Flinkeddatahub.com%2Fgraphs%2Fc5f34fe9-0456-48e8-a371-04be71529762 > >>>>>>>>>>>>> HTTP/1.1 > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> Often you want to query different amounts of data > >>>>>>>>>>>>> depending of the case. Sometimes for example, person name > >>>>>>>>>>>>> is enough, other time you want all the triples (DESCRIBE). > >>>>>>>>>>>>> How do you specify here the context? > >>>>>>>>>>>>> > >>>>>>>>>>>>> BTW is there a dedicated forum for discussing Linked Data > >>>>>>>>>>>>> Templates? > >>>>>>>>>>> -- > >>>>>>>>>>> Lingsoft - 30 years of Leading Language Management > >>>>>>>>>>> > >>>>>>>>>>> www.lingsoft.fi > >>>>>>>>>>> > >>>>>>>>>>> Speech Applications - Language Management - Translation - > >>>>>>>>>>> Reader's and Writer's Tools - Text Tools - E-books and M-books > >>>>>>>>>>> > >>>>>>>>>>> Mikael Pesonen > >>>>>>>>>>> System Engineer > >>>>>>>>>>> > >>>>>>>>>>> e-mail: mikael.pesonen@lingsoft.fi > >>>>>>>>>>> Tel. +358 2 279 3300 > >>>>>>>>>>> > >>>>>>>>>>> Time zone: GMT+2 > >>>>>>>>>>> > >>>>>>>>>>> Helsinki Office > >>>>>>>>>>> Eteläranta 10 > >>>>>>>>>>> FI-00130 Helsinki > >>>>>>>>>>> FINLAND > >>>>>>>>>>> > >>>>>>>>>>> Turku Office > >>>>>>>>>>> Kauppiaskatu 5 A > >>>>>>>>>>> FI-20100 Turku > >>>>>>>>>>> FINLAND > >>>>>>>>>>> > >>>>>>>>> -- > >>>>>>>>> Lingsoft - 30 years of Leading Language Management > >>>>>>>>> > >>>>>>>>> www.lingsoft.fi > >>>>>>>>> > >>>>>>>>> Speech Applications - Language Management - Translation - > >>>>>>>>> Reader's and Writer's Tools - Text Tools - E-books and M-books > >>>>>>>>> > >>>>>>>>> Mikael Pesonen > >>>>>>>>> System Engineer > >>>>>>>>> > >>>>>>>>> e-mail: mikael.pesonen@lingsoft.fi > >>>>>>>>> Tel. +358 2 279 3300 > >>>>>>>>> > >>>>>>>>> Time zone: GMT+2 > >>>>>>>>> > >>>>>>>>> Helsinki Office > >>>>>>>>> Eteläranta 10 > >>>>>>>>> FI-00130 Helsinki > >>>>>>>>> FINLAND > >>>>>>>>> > >>>>>>>>> Turku Office > >>>>>>>>> Kauppiaskatu 5 A > >>>>>>>>> FI-20100 Turku > >>>>>>>>> FINLAND > >>>>>>>>> > >>>>>>> -- > >>>>>>> Lingsoft - 30 years of Leading Language Management > >>>>>>> > >>>>>>> www.lingsoft.fi > >>>>>>> > >>>>>>> Speech Applications - Language Management - Translation - > >>>>>>> Reader's and Writer's Tools - Text Tools - E-books and M-books > >>>>>>> > >>>>>>> Mikael Pesonen > >>>>>>> System Engineer > >>>>>>> > >>>>>>> e-mail: mikael.pesonen@lingsoft.fi > >>>>>>> Tel. +358 2 279 3300 > >>>>>>> > >>>>>>> Time zone: GMT+2 > >>>>>>> > >>>>>>> Helsinki Office > >>>>>>> Eteläranta 10 > >>>>>>> FI-00130 Helsinki > >>>>>>> FINLAND > >>>>>>> > >>>>>>> Turku Office > >>>>>>> Kauppiaskatu 5 A > >>>>>>> FI-20100 Turku > >>>>>>> FINLAND > >>>>>>> > >>>>> -- > >>>>> Lingsoft - 30 years of Leading Language Management > >>>>> > >>>>> www.lingsoft.fi > >>>>> > >>>>> Speech Applications - Language Management - Translation - Reader's > >>>>> and Writer's Tools - Text Tools - E-books and M-books > >>>>> > >>>>> Mikael Pesonen > >>>>> System Engineer > >>>>> > >>>>> e-mail: mikael.pesonen@lingsoft.fi > >>>>> Tel. +358 2 279 3300 > >>>>> > >>>>> Time zone: GMT+2 > >>>>> > >>>>> Helsinki Office > >>>>> Eteläranta 10 > >>>>> FI-00130 Helsinki > >>>>> FINLAND > >>>>> > >>>>> Turku Office > >>>>> Kauppiaskatu 5 A > >>>>> FI-20100 Turku > >>>>> FINLAND > >>>>> > >>> -- > >>> Lingsoft - 30 years of Leading Language Management > >>> > >>> www.lingsoft.fi > >>> > >>> Speech Applications - Language Management - Translation - Reader's > >>> and Writer's Tools - Text Tools - E-books and M-books > >>> > >>> Mikael Pesonen > >>> System Engineer > >>> > >>> e-mail: mikael.pesonen@lingsoft.fi > >>> Tel. +358 2 279 3300 > >>> > >>> Time zone: GMT+2 > >>> > >>> Helsinki Office > >>> Eteläranta 10 > >>> FI-00130 Helsinki > >>> FINLAND > >>> > >>> Turku Office > >>> Kauppiaskatu 5 A > >>> FI-20100 Turku > >>> FINLAND > >>> > > > > -- > Lingsoft - 30 years of Leading Language Management > > www.lingsoft.fi > > Speech Applications - Language Management - Translation - Reader's and Writer's Tools - Text Tools - E-books and M-books > > Mikael Pesonen > System Engineer > > e-mail: mikael.pesonen@lingsoft.fi > Tel. +358 2 279 3300 > > Time zone: GMT+2 > > Helsinki Office > Eteläranta 10 > FI-00130 Helsinki > FINLAND > > Turku Office > Kauppiaskatu 5 A > FI-20100 Turku > FINLAND >
Received on Tuesday, 17 September 2019 11:57:50 UTC