Merge pull request #94 from fastenhealth/elasticsearch-pagination
|
@ -47,11 +47,10 @@ make backend-test
|
|||
|
||||
# Start Development Environment
|
||||
|
||||
To run Fasten from source, you'll need to create 3 separate processes:
|
||||
To run Fasten from source, you'll need to create 2 separate processes:
|
||||
|
||||
- Angular Frontend
|
||||
- Go Backend
|
||||
- CouchDB Database
|
||||
|
||||
First we'll create a development config file (`config.dev.yaml`)
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
version: "3.9"
|
||||
services:
|
||||
couchdb:
|
||||
fasten:
|
||||
# NOTE: only developers need to build Fasten from source
|
||||
# For production, use the pre-built image from GitHub Packages
|
||||
# ghcr.io/fastenhealth/fasten-onprem:main
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
# environment:
|
||||
# - COUCHDB_USER=admin
|
||||
# - COUCHDB_PASSWORD=password
|
||||
args:
|
||||
- FASTEN_ENV=prod
|
||||
# - FASTEN_ENV=sandbox
|
||||
ports:
|
||||
- "9090:8080"
|
||||
- "5984:5984"
|
||||
volumes:
|
||||
- ./.couchdb/data:/opt/couchdb/data
|
||||
- ./.couchdb/config:/opt/couchdb/etc/local.d
|
||||
- ./db:/opt/fasten/db
|
||||
# - ./config.example.yaml:/opt/fasten/config/config.yaml
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
"bootstrap": "^4.4.1",
|
||||
"chart.js": "2.9.4",
|
||||
"fhirpath": "^3.3.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
"humanize-duration": "^3.27.3",
|
||||
"idb": "^7.1.0",
|
||||
"jose": "^4.10.4",
|
||||
|
@ -44,6 +43,7 @@
|
|||
"ng2-charts": "^2.3.0",
|
||||
"ngx-dropzone": "^3.1.0",
|
||||
"ngx-highlightjs": "^7.0.1",
|
||||
"ngx-infinite-scroll": "^14.0.0",
|
||||
"ngx-moment": "^6.0.2",
|
||||
"rxjs": "~6.5.4",
|
||||
"tslib": "^2.0.0",
|
||||
|
|
|
@ -30,7 +30,7 @@ import { MedicalHistoryComponent } from './pages/medical-history/medical-history
|
|||
import { ReportLabsComponent } from './pages/report-labs/report-labs.component';
|
||||
import {PipesModule} from './pipes/pipes.module';
|
||||
import { ResourceCreatorComponent } from './pages/resource-creator/resource-creator.component';
|
||||
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -62,6 +62,7 @@ import { ResourceCreatorComponent } from './pages/resource-creator/resource-crea
|
|||
HighlightModule,
|
||||
MomentModule,
|
||||
PipesModule,
|
||||
InfiniteScrollModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export class MetadataSource {
|
||||
platform_type: string
|
||||
brand_logo?: string
|
||||
source_type: string
|
||||
display: string
|
||||
category: string[]
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export class LighthouseSourceMetadata {
|
||||
import {MetadataSource} from '../fasten/metadata-source';
|
||||
|
||||
export class LighthouseSourceMetadata extends MetadataSource {
|
||||
|
||||
authorization_endpoint: string
|
||||
token_endpoint: string
|
||||
introspection_endpoint: string
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import {MetadataSource} from '../fasten/metadata-source';
|
||||
|
||||
export class LighthouseSourceSearch {
|
||||
_scroll_id: string;
|
||||
took: number;
|
||||
timed_out: boolean;
|
||||
hits: {
|
||||
total: {
|
||||
value: number;
|
||||
relation: string;
|
||||
};
|
||||
max_score: number;
|
||||
hits: {
|
||||
_index: string;
|
||||
_type: string;
|
||||
_id: string;
|
||||
_score: number;
|
||||
_source: MetadataSource;
|
||||
}[];
|
||||
};
|
||||
}
|
|
@ -43,6 +43,7 @@ export class DashboardComponent implements OnInit {
|
|||
this.metadataSource = metadataSource
|
||||
this.metadataSource["manual"] = {
|
||||
"source_type": "manual",
|
||||
"platform_type": "manual",
|
||||
"display": "Manual",
|
||||
"category": ["Manual"],
|
||||
"hidden": false,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
<div (click)="openModal(contentModalRef, sourceInfo)" class="card-body">
|
||||
|
||||
<div class="h-100 d-flex align-items-center">
|
||||
<img [src]="'assets/sources/'+sourceInfo?.metadata['source_type']+'.png'" [alt]="sourceInfo?.metadata.display" class="img-fluid">
|
||||
<img [src]="'assets/sources/'+(sourceInfo.metadata.brand_logo ? sourceInfo.metadata.brand_logo : sourceInfo.metadata.source_type+'.png')" [alt]="sourceInfo?.metadata.display" class="img-fluid">
|
||||
</div>
|
||||
<div *ngIf="status[sourceInfo.metadata?.source_type]" class="progress">
|
||||
<div [style.width]="status[sourceInfo?.metadata?.source_type] == 'authorize' ? '33%' : '66%'" class="bg-indigo progress-bar progress-bar-striped progress-bar-animated" role="progressbar"></div>
|
||||
|
@ -71,34 +71,38 @@
|
|||
|
||||
<!-- Search -->
|
||||
<div class="row row-sm sticky-top pt-2" style="position:sticky;">
|
||||
<div class="col-lg-4">
|
||||
<div class="col-lg-8">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="search-prefix">Search</span>
|
||||
</div>
|
||||
<input (keyup)="searchTermChanged($event)" type="text" class="form-control" placeholder="Search Term">
|
||||
<input (keyup)="searchTermUpdate.next($event.target.value)" type="text" class="form-control" placeholder="Search Term">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">{{this.availableSourceList.length}} of {{this.totalAvailableSourceList}} results</span>
|
||||
</div>
|
||||
|
||||
</div><!-- input-group -->
|
||||
</div><!-- col -->
|
||||
<!-- <div class="col-lg-4">-->
|
||||
<!-- <div class="d-flex text-center">-->
|
||||
<!-- <small>{{this.availableSourceList.length}} of {{this.totalAvailableSourceList}} sources</small>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
|
||||
|
||||
<div *ngIf="!loading else isLoadingTemplate" class="row row-sm">
|
||||
<div *ngIf="!loading else isLoadingTemplate" class="row row-sm"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="2"
|
||||
[infiniteScrollThrottle]="50"
|
||||
(scrolled)="onScroll()"
|
||||
>
|
||||
<div *ngFor="let sourceData of availableSourceList" (click)="connectHandler($event, sourceData.metadata.source_type)" class="col-sm-3 mg-b-20 px-3">
|
||||
<div class="card h-100 d-flex align-items-center justify-content-center mt-3 mt-3 rounded-0 cursor-pointer" [ngClass]="{'card-disable': sourceData.metadata.hidden}">
|
||||
<div class="card-body d-flex align-items-center">
|
||||
<img style="max-height: 130px;" [src]="'assets/sources/'+sourceData.metadata.source_type+'.png'" [alt]="metadataSources[sourceData.metadata.source_type].display" class="img-fluid">
|
||||
<img style="max-height: 130px;" [src]="'assets/sources/'+(sourceData.metadata.brand_logo ? sourceData.metadata.brand_logo : sourceData.metadata.source_type+'.png')" [alt]="sourceData.metadata.display" class="img-fluid">
|
||||
<div *ngIf="status[sourceData.metadata.source_type]" class="progress">
|
||||
<div [style.width]="status[sourceData.metadata.source_type] == 'authorize' ? '33%' : '66%'" class="bg-indigo progress-bar progress-bar-striped progress-bar-animated" role="progressbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-center p-1" style="width:100%">
|
||||
<small class="tx-gray-700">
|
||||
{{metadataSources[sourceData.metadata.source_type].display}}
|
||||
{{sourceData.metadata.display}}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,8 +10,9 @@ import {Location} from '@angular/common';
|
|||
import {ToastService} from '../../services/toast.service';
|
||||
import {ToastNotification, ToastType} from '../../models/fasten/toast';
|
||||
import {environment} from '../../../environments/environment';
|
||||
import {forkJoin} from 'rxjs';
|
||||
import Fuse from 'fuse.js'
|
||||
import {BehaviorSubject, forkJoin, Subject} from 'rxjs';
|
||||
import {LighthouseSourceSearch} from '../../models/lighthouse/lighthouse-source-search';
|
||||
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
|
||||
// If you dont import this angular will import the wrong "Location"
|
||||
|
||||
export const sourceConnectWindowTimeout = 24*5000 //wait 2 minutes (5 * 24 = 120)
|
||||
|
@ -32,8 +33,6 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
environment_name = environment.environment_name
|
||||
status: { [name: string]: string } = {}
|
||||
|
||||
metadataSources: {[name:string]: MetadataSource} = {}
|
||||
|
||||
connectedSourceList: SourceListItem[] = [] //source's are populated for this list
|
||||
availableSourceList: SourceListItem[] = []
|
||||
totalAvailableSourceList: number = 0
|
||||
|
@ -42,8 +41,10 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
closeResult = '';
|
||||
modalSelectedSourceListItem:SourceListItem = null;
|
||||
|
||||
searchIndex = null
|
||||
searchTerm: string = ""
|
||||
scrollId: string = ""
|
||||
scrollComplete: boolean = false
|
||||
searchTermUpdate = new BehaviorSubject<string>("");
|
||||
showHidden: boolean = false
|
||||
|
||||
constructor(
|
||||
private lighthouseApi: LighthouseService,
|
||||
|
@ -57,29 +58,20 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.loading = true
|
||||
forkJoin([this.lighthouseApi.getLighthouseSourceMetadataMap(false), this.fastenApi.getSources()]).subscribe(results => {
|
||||
forkJoin([this.lighthouseApi.findLighthouseSources("", "", this.showHidden), this.fastenApi.getSources()]).subscribe(results => {
|
||||
this.loading = false
|
||||
|
||||
//handle connected sources sources
|
||||
const connectedSources = results[1] as Source[]
|
||||
forkJoin(connectedSources.map((source) => this.lighthouseApi.getLighthouseSource(source.source_type))).subscribe((connectedMetadata) => {
|
||||
for(const ndx in connectedSources){
|
||||
this.connectedSourceList.push({source: connectedSources[ndx], metadata: connectedMetadata[ndx]})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//handle source metadata map response
|
||||
this.metadataSources = results[0] as {[name:string]: MetadataSource}
|
||||
|
||||
//handle sources
|
||||
const sourceList = results[1] as Source[]
|
||||
|
||||
for (const sourceType in this.metadataSources) {
|
||||
let isConnected = false
|
||||
for(const connectedSource of sourceList){
|
||||
if(connectedSource.source_type == sourceType){
|
||||
this.connectedSourceList.push({source: connectedSource, metadata: this.metadataSources[sourceType]})
|
||||
isConnected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if(!isConnected){
|
||||
//this source has not been found in the connected list, lets add it to the available list.
|
||||
this.availableSourceList.push({metadata: this.metadataSources[sourceType]})
|
||||
}
|
||||
}
|
||||
this.populateAvailableSourceList(results[0] as LighthouseSourceSearch)
|
||||
|
||||
|
||||
//check if we've just started connecting a "source_type"
|
||||
|
@ -97,55 +89,59 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
|
||||
this.callback(callbackSourceType).then(console.log)
|
||||
}
|
||||
this.totalAvailableSourceList = this.availableSourceList.length
|
||||
|
||||
//setup Search
|
||||
const options = {
|
||||
// isCaseSensitive: false,
|
||||
// includeScore: false,
|
||||
// shouldSort: true,
|
||||
// includeMatches: false,
|
||||
findAllMatches: true,
|
||||
// minMatchCharLength: 1,
|
||||
// location: 0,
|
||||
// threshold: 0.6,
|
||||
// distance: 100,
|
||||
// useExtendedSearch: false,
|
||||
// ignoreLocation: false,
|
||||
// ignoreFieldNorm: false,
|
||||
// fieldNormWeight: 1,
|
||||
keys: [
|
||||
"metadata.display",
|
||||
"metadata.category",
|
||||
"metadata.source_type"
|
||||
]
|
||||
};
|
||||
|
||||
this.searchIndex = new Fuse(this.availableSourceList, options);
|
||||
|
||||
|
||||
}, err => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
|
||||
//register a callback for when the search term changes
|
||||
this.searchTermUpdate
|
||||
.pipe(
|
||||
debounceTime(200),
|
||||
distinctUntilChanged(),
|
||||
)
|
||||
.subscribe(value => {
|
||||
console.log("search term changed:", value)
|
||||
|
||||
//reset available sources
|
||||
this.availableSourceList = []
|
||||
this.scrollId = ""
|
||||
this.scrollComplete = false
|
||||
this.totalAvailableSourceList = 0
|
||||
|
||||
this.lighthouseApi.findLighthouseSources(value, this.scrollId, this.showHidden)
|
||||
.subscribe((results) => {
|
||||
this.populateAvailableSourceList(results)
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public searchTermChanged($event):void {
|
||||
this.searchTerm = $event.target.value
|
||||
console.log("search term changed:", )
|
||||
private populateAvailableSourceList(results: LighthouseSourceSearch): void {
|
||||
this.totalAvailableSourceList = results.hits.total.value
|
||||
if(results.hits.hits.length == 0){
|
||||
this.scrollComplete = true
|
||||
console.log("scroll complete")
|
||||
return
|
||||
}
|
||||
this.scrollId = results._scroll_id
|
||||
this.availableSourceList = this.availableSourceList.concat(results.hits.hits.map((result) => {
|
||||
return {metadata: result._source}
|
||||
}).filter((item) => {
|
||||
return !this.connectedSourceList.find((connectedItem) => connectedItem.metadata.source_type == item.metadata.source_type)
|
||||
}))
|
||||
}
|
||||
|
||||
let searchResults
|
||||
if(this.searchTerm){
|
||||
searchResults = this.searchIndex.search(this.searchTerm).map((result) => {
|
||||
return result.item
|
||||
public onScroll(): void {
|
||||
if(this.scrollComplete){
|
||||
return
|
||||
}
|
||||
|
||||
this.lighthouseApi.findLighthouseSources(this.searchTermUpdate.getValue(), this.scrollId, this.showHidden)
|
||||
.subscribe((results) => {
|
||||
this.populateAvailableSourceList(results)
|
||||
})
|
||||
}
|
||||
else {
|
||||
//emtpy search term, show all (original) values.
|
||||
searchResults = this.searchIndex.getIndex().docs
|
||||
}
|
||||
|
||||
this.availableSourceList = searchResults
|
||||
console.log(this.availableSourceList)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,7 +218,14 @@ export class MedicalSourcesComponent implements OnInit {
|
|||
console.log("NO PATIENT ID present, decoding jwt to extract patient")
|
||||
//const introspectionResp = await Oauth.introspectionRequest(as, client, payload.access_token)
|
||||
//console.log(introspectionResp)
|
||||
payload.patient = this.jwtDecode(payload.id_token)["profile"].replace(/^(Patient\/)/,'')
|
||||
let decodedIdToken = this.jwtDecode(payload.id_token)
|
||||
//nextGen uses fhirUser instead of profile.
|
||||
payload.patient = decodedIdToken["profile"] || decodedIdToken["fhirUser"]
|
||||
|
||||
if(payload.patient){
|
||||
payload.patient = payload.patient.replace(/^(Patient\/)/,'')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as Oauth from '@panva/oauth4webapi';
|
|||
import {SourceState} from '../models/fasten/source-state';
|
||||
import {MetadataSource} from '../models/fasten/metadata-source';
|
||||
import {uuidV4} from '../../lib/utils/uuid';
|
||||
import {LighthouseSourceSearch} from '../models/lighthouse/lighthouse-source-search';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -18,6 +19,27 @@ export class LighthouseService {
|
|||
constructor(private _httpClient: HttpClient) {
|
||||
}
|
||||
|
||||
public findLighthouseSources(searchTerm: string, scrollId= "", showHidden = false): Observable<LighthouseSourceSearch> {
|
||||
const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list/search`);
|
||||
if(showHidden){
|
||||
endpointUrl.searchParams.set('show_hidden', 'true');
|
||||
}
|
||||
if(scrollId){
|
||||
endpointUrl.searchParams.set('scroll_id', scrollId);
|
||||
}
|
||||
if(searchTerm){
|
||||
endpointUrl.searchParams.set('query', searchTerm);
|
||||
}
|
||||
|
||||
return this._httpClient.get<ResponseWrapper>(endpointUrl.toString())
|
||||
.pipe(
|
||||
map((response: ResponseWrapper) => {
|
||||
console.log("Metadata RESPONSE", response)
|
||||
return response.data as LighthouseSourceSearch
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public getLighthouseSourceMetadataMap(showHidden = false): Observable<{[name: string]: MetadataSource}> {
|
||||
const endpointUrl = new URL(`${environment.lighthouse_api_endpoint_base}/list`);
|
||||
if(showHidden){
|
||||
|
|
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 6.2 KiB |
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="408px" height="104px" viewBox="0 0 408 104" enable-background="new 0 0 408 104" xml:space="preserve">
|
||||
<g>
|
||||
<defs>
|
||||
<rect id="SVGID_1_" x="4" y="4" width="400" height="96"/>
|
||||
</defs>
|
||||
<clipPath id="SVGID_2_">
|
||||
<use xlink:href="#SVGID_1_" overflow="visible"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#SVGID_2_)">
|
||||
<rect x="-3.115" y="-9.004" fill="#005ea6" width="430.518" height="109.004"/>
|
||||
<rect x="-1.113" y="82.424" fill="#FFFFFF" width="430.518" height="4.291"/>
|
||||
<rect x="-3.115" y="86.715" fill="#C41623" width="430.518" height="50.596"/>
|
||||
</g>
|
||||
</g>
|
||||
<path fill="#FFFFFF" d="M404,4v96H4V4H404 M408,0h-4H4H0v4v96v4h4h400h4v-4V4V0L408,0z"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M76.748,65.242c0-1.219,0-42.146,0-42.146h-13.23c0,0,0,39.166,0,40.318
|
||||
c0,6.277-5.355,10.016-12.926,10.016c-8.645,0-13.391-3.738-13.391-10.094c0-1.148,0-40.24,0-40.24H23.975c0,0,0,40.006,0,41.381
|
||||
c0,14.164,11.242,19.82,26.309,19.82c10.399,0,18.778-2.844,23.152-8.595v7.829h11.801V71.223h-9.428
|
||||
C76.419,69.417,76.748,67.427,76.748,65.242z"/>
|
||||
<path fill="#FFFFFF" d="M139.99,66.094c0-10.334-6.27-15.307-18.285-17.604c-1.379-0.23-5.359-1.074-8.41-1.684
|
||||
c-9.871-1.988-13.469-3.746-13.469-8.184c0-3.445,1.992-5.66,12.012-5.66c7.648,0,10.938,1.758,12.543,5.125
|
||||
c0.461,0.922,0.844,2.293,0.844,2.98h13.617c0-1.535-0.609-3.82-1.379-5.812c-3.055-7.648-10.172-12.926-25.32-12.926
|
||||
c-17.746,0-26.004,6.879-26.004,17.137c0,10.023,7.262,15.453,19.047,17.67c2.676,0.531,7.113,1.379,8.875,1.688
|
||||
c9.781,1.836,12.312,3.59,12.312,8.566c0,3.98-3.211,6.496-12.398,6.496c-8.027,0-12.004-1.523-13.688-5.043
|
||||
c-0.461-0.914-0.844-2.75-0.844-3.824H85.826c0,1.219,0.23,4.207,0.852,6.191c2.438,7.652,9.016,13.16,27.297,13.16
|
||||
c11.484,0,19.128-3.223,23.008-8.555v7.715h11.797V71.223h-9.529C139.729,69.62,139.99,67.912,139.99,66.094z"/>
|
||||
<polygon fill="#FFFFFF" points="191.463,62.031 168.209,23.096 152.834,23.096 152.834,83.531 165.455,83.531 165.455,42.6
|
||||
189.783,83.531 204.084,83.531 204.084,23.096 191.463,23.096 "/>
|
||||
<path fill="#FFFFFF" d="M233.311,37.896c-9.73,0-17.43,3.645-21.727,9.887c-2.508,3.566-3.891,8.102-3.891,13.209
|
||||
c0,5.598,1.215,10.055,3.41,13.539c4.293,6.812,12.312,9.727,22.207,9.727c7.211,0,12.648-1.539,16.543-4.047
|
||||
c4.453-2.848,7.047-6.895,8.094-11.191h-12.727c-0.238,0.977-1.375,2.43-3.719,3.484c-1.871,0.812-4.543,1.461-8.191,1.461
|
||||
c-4.863,0-8.504-1.293-10.379-3.32c-1.535-1.703-2.43-3.238-2.43-5.277h37.773c0.727-6.719-0.488-13.127-3.812-17.99
|
||||
C250.498,41.619,243.521,37.896,233.311,37.896z M220.42,56.863c0-1.303,1.219-3.971,2.758-5.35
|
||||
c2.191-1.945,5.598-3.168,10.211-3.168c4.867,0,7.945,1.547,9.816,3.41c1.617,1.703,2.172,3.805,2.172,5.107H220.42z"/>
|
||||
<path fill="#FFFFFF" d="M325.107,38.951l-10.449,33.146l-10.055-33.146h-14.422l-9.805,33.146l-10.699-33.146h-13.535l15.953,44.58
|
||||
h15.414c0,0,8.758-25.613,8.836-27.158c0.082-0.488,0.559-3.129,0.559-3.129s0.492,2.641,0.578,3.211
|
||||
c0.156,1.463,8.918,27.076,8.918,27.076h15.316l16.129-44.58H325.107z"/>
|
||||
<path fill="#FFFFFF" d="M368.623,56.455c-1.535-0.242-7.777-1.141-10.371-1.535c-6.32-0.977-7.707-1.703-7.707-3.648
|
||||
c0-2.102,2.113-3.246,9.25-3.246c6.156,0,8.504,1.062,9.398,2.273c0.398,0.566,0.57,1.941,0.57,2.426h12.562
|
||||
c0-0.891-0.246-3.637-0.812-5.348c-2.266-6.398-9.977-9.559-22.207-9.559c-14.352,0-21.477,5.188-21.477,13.121
|
||||
c0,8.521,4.699,12.814,14.508,14.189c2.672,0.406,8.023,1.219,9.719,1.461c6.566,0.973,9.246,1.535,9.246,4.055
|
||||
c0,2.59-2.27,3.887-9.645,3.887c-7.055,0-10.457-0.566-11.27-2.672c-0.324-0.895-0.402-1.703-0.402-2.273H337.1
|
||||
c0,1.461,0.078,2.68,0.48,4.461c1.867,7.297,8.996,10.289,24.078,10.289c15.398,0,22.367-4.699,22.367-13.938
|
||||
C384.025,62.051,379.318,58.078,368.623,56.455z"/>
|
||||
<path fill="#FFFFFF" d="M215.045,35.334c1.156,0,2.406-0.195,3.344-0.586c0.172,0.152,0.367,0.32,0.57,0.465h4.621
|
||||
c-0.879-0.699-1.797-1.406-2.605-2.004c0.973-0.926,1.59-2.242,1.648-3.766h-3.406c-0.035,0.695-0.258,1.34-0.656,1.844
|
||||
c-0.699-0.574-1.398-1.199-1.945-1.645c1.211-0.75,2.391-1.82,2.43-3.359c0-0.082,0.016-0.418,0-0.527
|
||||
c-0.086-1.473-1.434-2.812-3.746-2.812c-2.531,0-3.996,1.414-4.062,2.906c0,0.195,0,0.477,0,0.617
|
||||
c0.02,0.734,0.289,1.566,0.996,2.566c-1.438,0.676-2.75,1.535-2.781,2.918c0,0.156-0.012,0.438,0,0.629
|
||||
C209.557,34.807,212.158,35.334,215.045,35.334z M214.447,26.338c0.051-0.43,0.277-0.797,0.816-0.797
|
||||
c0.559,0,0.75,0.352,0.77,0.754c0,0.043,0,0.172,0,0.246c-0.039,0.473-0.473,0.875-1.094,1.242
|
||||
c-0.301-0.395-0.473-0.781-0.492-1.117C214.432,26.564,214.432,26.436,214.447,26.338z M214.006,31.068
|
||||
c0.512,0.516,1.234,1.078,1.93,1.676c-0.301,0.078-0.719,0.121-1.062,0.121c-1.266,0-1.809-0.223-1.809-0.809
|
||||
C213.064,31.713,213.451,31.381,214.006,31.068z"/>
|
||||
<path fill="#FFFFFF" d="M234.068,35.213c0,0,1.859-6.984,1.879-7.391c0.047,0.391,1.863,7.391,1.863,7.391h4.062l3.406-12.145
|
||||
h-3.605c0,0-1.824,7.5-1.824,7.883c0-0.383-1.844-7.883-1.844-7.883h-3.82c0,0-1.797,7.5-1.797,7.883
|
||||
c0-0.383-1.855-7.883-1.855-7.883h-3.973l3.477,12.145H234.068z"/>
|
||||
<path fill="#FFFFFF" d="M251.893,35.396c4.445,0,6.473-2.098,6.473-6.363c0-4.059-1.891-6.184-6.473-6.184
|
||||
c-4.492,0-6.48,2.355-6.48,6.23C245.412,33.229,247.436,35.396,251.893,35.396z M251.893,25.721c2.059,0,2.719,0.992,2.719,3.398
|
||||
c0,2.707-0.992,3.43-2.699,3.43c-1.777,0-2.707-0.855-2.707-3.43C249.205,26.678,249.912,25.721,251.893,25.721z"/>
|
||||
<path fill="#FFFFFF" d="M263.678,31.104h2.512l2.133,4.109h4.172l-2.84-4.863c0.562-0.125,1.109-0.504,1.492-1.152
|
||||
c0.324-0.539,0.535-1.312,0.535-2.289c0-1.137-0.227-1.953-0.699-2.566c-0.613-0.809-1.664-1.273-3.281-1.273h-7.688v12.145h3.664
|
||||
V31.104z M263.713,25.928h3.133c0.539,0,0.895,0.117,1.074,0.508c0.105,0.18,0.133,0.508,0.133,0.781
|
||||
c0,0.242-0.047,0.566-0.141,0.781c-0.137,0.301-0.527,0.406-0.984,0.406h-3.215V25.928z"/>
|
||||
<polygon fill="#FFFFFF" points="283.842,32.209 278.01,32.209 278.01,23.068 274.252,23.068 274.252,35.213 283.842,35.213 "/>
|
||||
<path fill="#FFFFFF" d="M296.709,33.451c0.672-1.008,0.855-1.957,0.855-4.547c0-2.211-0.145-3.223-0.891-4.254
|
||||
c-0.75-1.043-2.117-1.582-4.312-1.582h-6.664v12.145h6.844C294.725,35.213,295.979,34.572,296.709,33.451z M289.393,32.346v-6.438
|
||||
h2.344c0.918,0,1.363,0.137,1.836,0.656c0.297,0.344,0.383,1.469,0.383,2.34c0,0.988-0.035,2.363-0.352,2.75
|
||||
c-0.418,0.492-0.918,0.691-1.867,0.691H289.393z"/>
|
||||
<path fill="#FFFFFF" d="M307.408,31.104h2.508l2.145,4.109h4.164l-2.844-4.863c0.559-0.125,1.117-0.504,1.496-1.152
|
||||
c0.32-0.539,0.535-1.312,0.535-2.289c0-1.137-0.227-1.953-0.699-2.566c-0.613-0.809-1.664-1.273-3.281-1.273h-7.684v12.145h3.66
|
||||
V31.104z M307.443,25.928h3.125c0.535,0,0.902,0.117,1.09,0.508c0.094,0.18,0.117,0.508,0.117,0.781
|
||||
c0,0.242-0.039,0.566-0.133,0.781c-0.137,0.301-0.539,0.406-0.992,0.406h-3.207V25.928z"/>
|
||||
<polygon fill="#FFFFFF" points="328.525,32.381 321.791,32.381 321.791,30.576 328.213,30.576 328.213,27.689 321.791,27.689
|
||||
321.791,25.928 328.459,25.928 328.459,23.068 318.135,23.068 318.135,35.213 328.525,35.213 "/>
|
||||
<path fill="#FFFFFF" d="M334.65,31.412c0,0,3.285,0.027,3.742,0.02c1.492-0.031,2.656-0.418,3.355-1.234
|
||||
c0.605-0.645,0.898-1.598,0.898-2.945c0-1.508-0.383-2.555-1.094-3.168c-0.664-0.691-1.707-1.016-3.172-1.016h-7.473v12.145h3.742
|
||||
V31.412z M334.604,25.893h2.965c0.613,0,0.965,0.188,1.172,0.574c0.113,0.164,0.164,0.477,0.164,0.855
|
||||
c0,0.355-0.031,0.582-0.152,0.801c-0.176,0.336-0.523,0.57-1.23,0.57c-0.02,0-2.918,0-2.918,0V25.893z"/>
|
||||
<path fill="#FFFFFF" d="M350.436,35.396c4.438,0,6.469-2.098,6.469-6.363c0-4.059-1.895-6.184-6.469-6.184
|
||||
c-4.5,0-6.488,2.355-6.488,6.23C343.947,33.229,345.971,35.396,350.436,35.396z M350.436,25.721c2.059,0,2.711,0.992,2.711,3.398
|
||||
c0,2.707-0.992,3.43-2.707,3.43c-1.773,0-2.695-0.855-2.695-3.43C347.744,26.678,348.443,25.721,350.436,25.721z"/>
|
||||
<path fill="#FFFFFF" d="M362.256,31.104h2.512l2.141,4.109h4.16l-2.836-4.863c0.57-0.125,1.113-0.504,1.504-1.152
|
||||
c0.312-0.539,0.531-1.312,0.531-2.289c0-1.137-0.238-1.953-0.703-2.566c-0.617-0.809-1.68-1.273-3.289-1.273h-7.684v12.145h3.664
|
||||
V31.104z M362.287,25.928h3.133c0.531,0,0.898,0.117,1.082,0.508c0.094,0.18,0.121,0.508,0.121,0.781
|
||||
c0,0.242-0.043,0.566-0.133,0.781c-0.133,0.301-0.539,0.406-0.996,0.406h-3.207V25.928z"/>
|
||||
<polygon fill="#FFFFFF" points="375.213,35.213 378.998,35.213 378.998,25.99 382.881,25.99 382.881,23.068 371.361,23.068
|
||||
371.361,25.99 375.213,25.99 "/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 9.0 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="42" viewBox="0 0 130 42"><defs><style>.cls-1{fill:#00a651;}.cls-2{fill:#00aeef;}.cls-3{fill:#16becf;}.cls-4{fill:#3dba93;}.cls-5{fill:#0eb46e;}</style></defs><title>AHNlogo_SVG_fixedsize</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="AHN_Logo_RGB" data-name="AHN Logo RGB"><g id="Group_21960" data-name="Group 21960"><g id="Group_13369" data-name="Group 13369"><path id="Path_6217" data-name="Path 6217" class="cls-1" d="M61.59,13c.3,1.18.59,2.37.89,3.25l2,6.31-5.84.2,2-6.31a34,34,0,0,0,1-3.45M58,6.31,48.54,35.79h6.52l2.48-8.09h8.3l2.57,8.09h6.72L65.45,6.31Z"/></g><path id="Path_6218" data-name="Path 6218" class="cls-1" d="M95.1,17.65h-11V6.31H77.8V35.79h6.33V23.27h11V35.79h6.23V6.31H95.1Z"/><g id="Group_13370" data-name="Group 13370"><path id="Path_6219" data-name="Path 6219" class="cls-1" d="M124,6.31V16.76c0,3.35.1,6.31.3,9.07a53.49,53.49,0,0,0-3.75-7L113,6.41h-6.72V35.89h5.84V25.14c0-3.75,0-6.8-.1-9.76,1.08,2.27,2.47,4.83,4.15,7.69l7.61,12.72H130V6.31Z"/><path id="Path_6220" data-name="Path 6220" class="cls-2" d="M16.51,34.41A66.83,66.83,0,0,1,21.85,42a65.58,65.58,0,0,1,5.34-7.59,57.26,57.26,0,0,0-5.34-7.59,78.46,78.46,0,0,0-5.34,7.59"/><path id="Path_6221" data-name="Path 6221" class="cls-3" d="M22.74,25.93a46.51,46.51,0,0,1,5.34,7.49,57.17,57.17,0,0,1,6.52-6.31,55.56,55.56,0,0,0-5.24-7.49,50,50,0,0,0-6.62,6.31m-1.68,0a51.18,51.18,0,0,0-5.34,7.49,57.26,57.26,0,0,0-6.53-6.31,56.2,56.2,0,0,1,5.24-7.49,50.09,50.09,0,0,1,6.63,6.31"/><path id="Path_6222" data-name="Path 6222" class="cls-1" d="M30.05,5.32A43.05,43.05,0,0,0,22,0a36.06,36.06,0,0,0-8.11,5.32A69.05,69.05,0,0,1,22,10.75a46.4,46.4,0,0,1,8.1-5.43"/><path id="Path_6223" data-name="Path 6223" class="cls-4" d="M21.85,12.22a59,59,0,0,0-6.72,6.41,59.88,59.88,0,0,1,6.72,6.31,50.82,50.82,0,0,1,6.72-6.31,52.21,52.21,0,0,0-6.72-6.41M5.44,13.6A68.71,68.71,0,0,0,0,21.2a49.78,49.78,0,0,1,8.11,5,52.4,52.4,0,0,1,5.24-7.49Q9.53,16,5.44,13.6m25,5.23a83.51,83.51,0,0,1,7.91-5.13,69.92,69.92,0,0,1,5.44,7.59,50.1,50.1,0,0,0-8.11,5,53.22,53.22,0,0,0-5.24-7.49"/><path id="Path_6224" data-name="Path 6224" class="cls-5" d="M20.86,11.44a71.27,71.27,0,0,0-8.11-5.33,66.86,66.86,0,0,0-6.42,6.51,70.17,70.17,0,0,1,7.91,5.22,50.07,50.07,0,0,1,6.62-6.4m2.08,0A70.27,70.27,0,0,1,31,6.11a67,67,0,0,1,6.43,6.51,68.41,68.41,0,0,0-7.91,5.22,51.33,51.33,0,0,0-6.62-6.4"/></g></g></g></g></g></svg>
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 4.4 KiB |