- From: Mikael Pesonen <mikael.pesonen@lingsoft.fi>
- Date: Tue, 17 Sep 2019 15:26:36 +0300
- To: Martynas Jusevičius <martynas@atomgraph.com>
- Cc: public-declarative-apps@w3.org
Thank you very much for the help. I'll setup the system next and see how it works out. Br, Mikael On 17/09/2019 14:57, Martynas Jusevičius wrote: > 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 >> -- 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 12:27:06 UTC