Commit eae62ae7 authored by Célia Michotey's avatar Célia Michotey
Browse files

Add About, Help, How to join and Legal mentions links in FAIDARE navbar. GNP-5519.

parent 222522d8
# About this application
# Help section
# How to join FAIDARE federation?
# General Terms of Use
By browsing this web site, you acknowledge and accept its general terms of use described below.
## Intellectual property
Except where otherwise noted, content on this site is licensed under a [Creative Commons Attribution 4.0 International license](https://creativecommons.org/licenses/by/4.0/).
The logo is the property of INRA and you are not allowed to re-use it for your own work and purpose.
## Content
The portal maintained by INRA allows to find public data across a federation of databases.
The licences associated to data are therefore defined by the institutes in charge of them.
Users are sole responsible for the searches they carry out, as well as for the interpretation and for the use they make of the results.
The access to the web site can be interrupted at any moment and without prior warning in case of force majeure or if the editor decides to terminate its provision of service.
Users are informed that their use of the results should not infringe on current legislation or the recommendations of the French Data Protection Authority (CNIL) with respect to personal data.
Users are warned that the information must be used for strictly professional purposes only and downloading screen shots in order to constitute or enrich a database is contrary to French law and therefore forbidden, as is its use for commercial or advertising purposes (CNIL).
The portal may give access to personal and professional data concerning technical and scientific actors in relation with the data.
This information helps to identify and acknowledge the authors of the scientific works.
This personal information is attached to the produced datasets and follows the data life cycle.
## Hyperlinks
The portal links to external web sites.
INRA does not take responsibility of the content of these web site.
## Personal data
Technical data (date, hour, IP address of the computer of the visitor, pages viewed) are collected only for the statistical analysis of the usage of the portal.
These data are kept confidential and not transmitted to any other party.
They are stored on INRA’s private servers for 5 years.
During visits on URGI web site and its hosted applications, a cookie can be automatically installed on visitor’s web browsers to retrieve statistics on the pages that are visited and support improvements of the services provided by the web site.
Visitors can configure their web browsers in order to be informed of the setting of cookies and refuse them.
According to the European Regulation on the protection of personal data (EU Regulation 2016/679), you have the right to access, rectify, oppose and delete information about yourself.
If you wish to exercise this right and obtain information about yourself, please contact us:
- By [email](mailto:urgi-contact@inra.fr?subject=%5BData%20Discovery%5D%20GPDR%20request)
- Or via any other way available on our [contact form](https://urgi.versailles.inra.fr/Contact-us)
## Modifications
The editor might change the terms of use and user’s rights without prior warning.
Last update: 2019 June 25th
package fr.inra.urgi.faidare.config;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.MimeMappings;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Configuration;
/**
* MimeMappings configuration. Ensure that markdown files are correctly returned with the good MimeType
* @author R. Flores
*/
@Configuration
public class MimeMappingServletCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.add("md", "text/markdown");
factory.setMimeMappings(mappings);
}
}
...@@ -75,6 +75,7 @@ server: ...@@ -75,6 +75,7 @@ server:
- application/javascript - application/javascript
- text/html - text/html
- text/css - text/css
- text/markdown
port: 8380 port: 8380
servlet: servlet:
context-path: /faidare-dev context-path: /faidare-dev
......
...@@ -857,6 +857,11 @@ ...@@ -857,6 +857,11 @@
"@types/leaflet": "*" "@types/leaflet": "*"
} }
}, },
"@types/marked": {
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.6.5.tgz",
"integrity": "sha512-6kBKf64aVfx93UJrcyEZ+OBM5nGv4RLsI6sR1Ar34bpgvGVRoyTgpxn4ZmtxOM5aDTAaaznYuYUH8bUX3Nk3YA=="
},
"@types/node": { "@types/node": {
"version": "8.9.5", "version": "8.9.5",
"resolved": "http://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", "resolved": "http://registry.npmjs.org/@types/node/-/node-8.9.5.tgz",
...@@ -2227,6 +2232,17 @@ ...@@ -2227,6 +2232,17 @@
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true "dev": true
}, },
"clipboard": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz",
"integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==",
"optional": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"cliui": { "cliui": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
...@@ -2860,6 +2876,12 @@ ...@@ -2860,6 +2876,12 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true "dev": true
}, },
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"optional": true
},
"delegates": { "delegates": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
...@@ -4484,6 +4506,15 @@ ...@@ -4484,6 +4506,15 @@
"minimatch": "~3.0.2" "minimatch": "~3.0.2"
} }
}, },
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"optional": true,
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": { "graceful-fs": {
"version": "4.1.15", "version": "4.1.15",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
...@@ -6235,6 +6266,11 @@ ...@@ -6235,6 +6266,11 @@
"object-visit": "^1.0.0" "object-visit": "^1.0.0"
} }
}, },
"marked": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.6.2.tgz",
"integrity": "sha512-LqxwVH3P/rqKX4EKGz7+c2G9r98WeM/SW34ybhgNGhUQNKtf1GmmSkJ6cDGJ/t6tiyae49qRkpyTw2B9HOrgUA=="
},
"md5.js": { "md5.js": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
...@@ -6592,6 +6628,17 @@ ...@@ -6592,6 +6628,17 @@
"resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-7.6.0.tgz", "resolved": "https://registry.npmjs.org/ng-mocks/-/ng-mocks-7.6.0.tgz",
"integrity": "sha512-Zorpd5I6KmvTtiYwcjymzCaortznMZr5CRB737XaNheITTUb2rVLUoEBk1dwQE3b/Cp5sByuS85fzwJRvjEXKQ==" "integrity": "sha512-Zorpd5I6KmvTtiYwcjymzCaortznMZr5CRB737XaNheITTUb2rVLUoEBk1dwQE3b/Cp5sByuS85fzwJRvjEXKQ=="
}, },
"ngx-markdown": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-8.0.2.tgz",
"integrity": "sha512-dLF205/JrSI7pOIgsrikhf9KYF6yiP797FuHGjVEw51KhHfuhCoR+3pl7Ky2vxuQBJjmkNGbgH75+Qy2SAnFEg==",
"requires": {
"@types/marked": "^0.6.0",
"marked": "^0.6.0",
"prismjs": "^1.16.0",
"tslib": "^1.9.0"
}
},
"ngx-moment": { "ngx-moment": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/ngx-moment/-/ngx-moment-3.3.0.tgz", "resolved": "https://registry.npmjs.org/ngx-moment/-/ngx-moment-3.3.0.tgz",
...@@ -7531,6 +7578,14 @@ ...@@ -7531,6 +7578,14 @@
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true "dev": true
}, },
"prismjs": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz",
"integrity": "sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==",
"requires": {
"clipboard": "^2.0.0"
}
},
"process": { "process": {
"version": "0.11.10", "version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
...@@ -8321,6 +8376,12 @@ ...@@ -8321,6 +8376,12 @@
} }
} }
}, },
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"optional": true
},
"select-hose": { "select-hose": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
...@@ -9526,6 +9587,12 @@ ...@@ -9526,6 +9587,12 @@
"setimmediate": "^1.0.4" "setimmediate": "^1.0.4"
} }
}, },
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"tmp": { "tmp": {
"version": "0.0.33", "version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
"leaflet.markercluster": "1.4.1", "leaflet.markercluster": "1.4.1",
"moment": "2.24.0", "moment": "2.24.0",
"ng-mocks": "^7.6.0", "ng-mocks": "^7.6.0",
"ngx-markdown": "^8.0.2",
"ngx-moment": "3.3.0", "ngx-moment": "3.3.0",
"popper.js": "1.14.6", "popper.js": "1.14.6",
"rxjs": "6.4.0", "rxjs": "6.4.0",
......
...@@ -4,12 +4,19 @@ import { ResultPageComponent } from './result-page/result-page.component'; ...@@ -4,12 +4,19 @@ import { ResultPageComponent } from './result-page/result-page.component';
import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component'; import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component';
import { StudyCardComponent } from './study-card/study-card.component'; import { StudyCardComponent } from './study-card/study-card.component';
import { SiteCardComponent } from './site-card/site-card.component'; import { SiteCardComponent } from './site-card/site-card.component';
import { MarkdownPageComponent } from "./markdown-page/markdown-page.component";
import { environment } from "../environments/environment";
export const routes: Routes = [ export const routes: Routes = [
{ path: 'studies/:id', component: StudyCardComponent }, { path: 'studies/:id', component: StudyCardComponent },
{ path: 'sites/:id', component: SiteCardComponent }, { path: 'sites/:id', component: SiteCardComponent },
{ path: '', component: ResultPageComponent }, { path: '', component: ResultPageComponent },
{ path: 'germplasm', component: GermplasmCardComponent } { path: 'germplasm', component: GermplasmCardComponent },
{ path: 'about', component: MarkdownPageComponent, data: { mdFile: environment.aboutUsMdFile } },
{ path: 'join', component: MarkdownPageComponent, data: { mdFile: environment.joinUsMdFile } },
{ path: 'legal', component: MarkdownPageComponent, data: { mdFile: environment.legalMentionsMdFile } },
{ path: 'help', component: MarkdownPageComponent, data: { mdFile: environment.helpMdFile } },
]; ];
@NgModule({ @NgModule({
......
...@@ -7,7 +7,7 @@ import { ResultPageComponent } from './result-page/result-page.component'; ...@@ -7,7 +7,7 @@ import { ResultPageComponent } from './result-page/result-page.component';
import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component'; import { GermplasmCardComponent } from './germplasm-card/germplasm-card.component';
import { StudyCardComponent } from './study-card/study-card.component'; import { StudyCardComponent } from './study-card/study-card.component';
import { SiteCardComponent } from './site-card/site-card.component'; import { SiteCardComponent } from './site-card/site-card.component';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
import { NavbarComponent } from './navbar/navbar.component'; import { NavbarComponent } from './navbar/navbar.component';
import { MapComponent } from './map/map.component'; import { MapComponent } from './map/map.component';
import { NgbAlertModule, NgbDropdownModule, NgbPaginationModule, NgbPopoverModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbAlertModule, NgbDropdownModule, NgbPaginationModule, NgbPopoverModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
...@@ -26,7 +26,8 @@ import { MomentModule } from 'ngx-moment'; ...@@ -26,7 +26,8 @@ import { MomentModule } from 'ngx-moment';
import { XrefsComponent } from './xrefs/xrefs.component'; import { XrefsComponent } from './xrefs/xrefs.component';
import { CoordinatesModule } from 'angular-coordinates'; import { CoordinatesModule } from 'angular-coordinates';
import { CardGenericDocumentComponent } from './card-generic-document/card-generic-document.component'; import { CardGenericDocumentComponent } from './card-generic-document/card-generic-document.component';
import { MarkdownModule, MarkedOptions, MarkedRenderer } from "ngx-markdown";
import { MarkdownPageComponent } from "./markdown-page/markdown-page.component";
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -48,7 +49,8 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener ...@@ -48,7 +49,8 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener
LoadingSpinnerComponent, LoadingSpinnerComponent,
CardTableComponent, CardTableComponent,
XrefsComponent, XrefsComponent,
CardGenericDocumentComponent CardGenericDocumentComponent,
MarkdownPageComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -62,7 +64,24 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener ...@@ -62,7 +64,24 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
MomentModule, MomentModule,
CoordinatesModule CoordinatesModule,
MarkdownModule.forRoot({
loader: HttpClient, // optional, only if you use [src] attribute
markedOptions: {
provide: MarkedOptions,
useFactory: markedOptionsFactory,
useValue: {
gfm: true, // default
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
smartLists: true,
smartypants: false
},
}
}),
], ],
providers: [ providers: [
{ provide: HTTP_INTERCEPTORS, useExisting: ErrorInterceptorService, multi: true } { provide: HTTP_INTERCEPTORS, useExisting: ErrorInterceptorService, multi: true }
...@@ -71,3 +90,19 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener ...@@ -71,3 +90,19 @@ import { CardGenericDocumentComponent } from './card-generic-document/card-gener
}) })
export class AppModule { export class AppModule {
} }
export function markedOptionsFactory(): MarkedOptions {
const renderer = new MarkedRenderer();
renderer.link = (href: string, title: string, text: string) => {
if (href.startsWith('#')) {
const fragment = href.split('#')[1];
return `<a href='${location.pathname}#${fragment}'>${text}</a>`;
}
return `<a href="${href}" target="_blank" >${text}</a>`;
};
return {
renderer: renderer
};
}
<markdown [src]="mdFile" lineNumbers="true" (error)="onError($event)"
(load)="onLoad($event)"></markdown>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MarkdownPageComponent } from './markdown-page.component';
import { ActivatedRoute } from "@angular/router";
import { environment } from "../../environments/environment";
import { of } from "rxjs";
describe('MarkdownPageComponent', () => {
let component: MarkdownPageComponent;
let fixture: ComponentFixture<MarkdownPageComponent>;
const route = ({ data: of({ mdFile: environment.helpMdFile }) } as any) as ActivatedRoute;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MarkdownPageComponent ],
providers: [{ provide: ActivatedRoute, useValue: route }],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MarkdownPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
expect(component.mdFile).toEqual('assets/help.md');
});
});
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from "@angular/router";
@Component({
selector: 'dd-about',
templateUrl: './markdown-page.component.html',
styleUrls: ['./markdown-page.component.scss']
})
export class MarkdownPageComponent implements OnInit {
mdFile: string = "";
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.route.data.subscribe(
value => this.mdFile = value.mdFile);
}
onLoad(e: any) {
// console.log('Into onLoad');
// console.log(e);
}
onError(e: any) {
console.log('Got error', e);
}
}
...@@ -18,27 +18,42 @@ ...@@ -18,27 +18,42 @@
<!-- OR Dropdown button --> <!-- OR Dropdown button -->
<div class="mr-2" *ngIf="link.subMenu" class="dropdown-container" ngbDropdown> <div class="mr-2" *ngIf="link.subMenu" class="dropdown-container" ngbDropdown>
<!-- Toggle button --> <!-- Toggle button -->
<a class="nav-link d-flex align-items-center dropdown-toggle" ngbDropdownToggle <a class="nav-link d-flex align-items-center dropdown-toggle" ngbDropdownToggle
role="button" role="button"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">{{ link.label }}</a>
{{ link.label }}
</a>
<!-- Items --> <!-- Items -->
<div class="dropdown-menu" ngbDropdownMenu> <div class="dropdown-menu" ngbDropdownMenu>
<div *ngFor="let subItem of link.subMenu"> <div *ngFor="let subItem of link.subMenu">
<a class="dropdown-item" <a class="dropdown-item"
target="_blank" target="_blank" [href]="subItem.url">{{ subItem.label }}</a>
[href]="subItem.url">
{{ subItem.label }}
</a>
</div> </div>
</div> </div>
</div> </div>
</li> </li>
<!-- Documentation -->
<li class="nav-item">
<div class="mr-2" class="dropdown-container" ngbDropdown>
<a class="nav-link d-flex align-items-center dropdown-toggle" ngbDropdownToggle
role="button"
aria-haspopup="true"
aria-expanded="false">
More ...
</a>
<div class="dropdown-menu" ngbDropdownMenu>
<!-- About link -->
<a class="dropdown-item" routerLink="/about" routerLinkActive="true" title="About">About</a>
<!-- Join us link -->
<a class="dropdown-item" routerLink="/join" routerLinkActive="true" title="Join us">Join us</a>
<!-- Legal mentions link -->
<a class="dropdown-item" routerLink="/legal" routerLinkActive="true" title="Legal mentions" >Legal mentions</a>
<!-- Help link -->
<a class="dropdown-item" routerLink="/help" routerLinkActive="true" title="Help">Help</a>
</div>
</div>
</li>
</ul> </ul>
</div> </div>
<a class="navbar-brand d-flex align-items-center" <a class="navbar-brand d-flex align-items-center"
......
import { async, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NavbarComponent } from './navbar.component'; import { NavbarComponent } from './navbar.component';
import { ComponentTester } from 'ngx-speculoos'; import { ComponentTester } from 'ngx-speculoos';
...@@ -20,7 +20,15 @@ class NavbarComponentTester extends ComponentTester<NavbarComponent> { ...@@ -20,7 +20,15 @@ class NavbarComponentTester extends ComponentTester<NavbarComponent> {
} }
get links() { get links() {
return this.elements('li a'); return this.elements('li');
}
get firstLink() {
return this.element('li').element('a');
}
get firstLinkSubLinks() {
return this.element('li').elements('a');
} }
get logo() { get logo() {
...@@ -30,42 +38,9 @@ class NavbarComponentTester extends ComponentTester<NavbarComponent> { ...@@ -30,42 +38,9 @@ class NavbarComponentTester extends ComponentTester<NavbarComponent> {
describe('NavbarComponent', () => { describe('NavbarComponent', () => {
const dataSource1: DataDiscoverySource = { beforeEach(() => TestBed.configureTestingModule({
'@id': 'urn:source1', declarations: [NavbarComponent]
'@type': ['schema:DataCatalog'], }));
'schema:name': 'Example source1',
'schema:url': 'http://example1.com',
'schema:image': 'http://example1.com/logo.png'
};
const dataSource2: DataDiscoverySource = {
'@id': 'urn:source2',
'@type': ['schema:DataCatalog'],
'schema:name': 'Example source2',
'schema:url': 'http://example2.com',
'schema:image': 'http://example2.com/logo.png'
};
<