diff --git a/src/atlasComponents/sapi/schemaV3.ts b/src/atlasComponents/sapi/schemaV3.ts
index 78aa3e006d082b8ba95dd50716a438dd98026c0c..16bccab868831ecaf188e2f3b5c7f1c0a55c4c5f 100644
--- a/src/atlasComponents/sapi/schemaV3.ts
+++ b/src/atlasComponents/sapi/schemaV3.ts
@@ -544,10 +544,16 @@ export interface components {
     FeatureMetaModel: {
       /** Name */
       name: string
+      /** Display Name */
+      display_name: string
       /** Path */
       path?: string
       /** Query Params */
       query_params?: (string)[]
+      /** Required Query Params */
+      required_query_params?: (string)[]
+      /** Optional Query Params */
+      optional_query_params?: (string)[]
       /** Path Params */
       path_params?: (string)[]
       /** Category */
@@ -716,6 +722,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[FeatureMetaModel] */
     Page_FeatureMetaModel_: {
@@ -727,6 +735,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[ParcellationEntityVersionModel] */
     Page_ParcellationEntityVersionModel_: {
@@ -738,6 +748,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraAtlasModel] */
     Page_SiibraAtlasModel_: {
@@ -749,6 +761,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraCorticalProfileModel] */
     Page_SiibraCorticalProfileModel_: {
@@ -760,6 +774,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraEbrainsDataFeatureModel] */
     Page_SiibraEbrainsDataFeatureModel_: {
@@ -771,6 +787,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraParcellationModel] */
     Page_SiibraParcellationModel_: {
@@ -782,6 +800,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraRegionalConnectivityModel] */
     Page_SiibraRegionalConnectivityModel_: {
@@ -793,6 +813,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraTabularModel] */
     Page_SiibraTabularModel_: {
@@ -804,6 +826,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[SiibraVoiModel] */
     Page_SiibraVoiModel_: {
@@ -815,6 +839,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** Page[Union[SiibraCorticalProfileModel, SiibraReceptorDensityFp, SiibraTabularModel]] */
     Page_Union_SiibraCorticalProfileModel__SiibraReceptorDensityFp__SiibraTabularModel__: {
@@ -826,6 +852,8 @@ export interface components {
       page: number
       /** Size */
       size: number
+      /** Pages */
+      pages?: number
     }
     /** ParcellationEntityVersionModel */
     ParcellationEntityVersionModel: {
@@ -1809,7 +1837,6 @@ export interface operations {
     parameters: {
       query: {
         space_id: string
-        bbox?: string
         type?: components["schemas"]["ImageTypes"]
       }
       path: {
diff --git a/src/atlasComponents/sapiViews/util/module.ts b/src/atlasComponents/sapiViews/util/module.ts
index 8d092a8c809ad7b3a42888a92b9becbf54ef6578..e863302c8626f285de94af0b4347b302a8ac715d 100644
--- a/src/atlasComponents/sapiViews/util/module.ts
+++ b/src/atlasComponents/sapiViews/util/module.ts
@@ -1,7 +1,6 @@
 import { NgModule } from "@angular/core";
 import { AddUnitAndJoin } from "./addUnitAndJoin.pipe";
 import { EqualityPipe } from "./equality.pipe";
-import { IncludesPipe } from "./includes.pipe";
 import { NumbersPipe } from "./numbers.pipe";
 import { ParseDoiPipe } from "./parseDoi.pipe";
 
@@ -11,14 +10,12 @@ import { ParseDoiPipe } from "./parseDoi.pipe";
     ParseDoiPipe,
     NumbersPipe,
     AddUnitAndJoin,
-    IncludesPipe,
   ],
   exports: [
     EqualityPipe,
     ParseDoiPipe,
     NumbersPipe,
     AddUnitAndJoin,
-    IncludesPipe,
   ]
 })
 
diff --git a/src/features/category-acc.directive.ts b/src/features/category-acc.directive.ts
index 353b405dca239768fa013f3aecd7aa921202d5ec..1ddb52d0c90c956c89f3ab62a0b6ee1f5518d586 100644
--- a/src/features/category-acc.directive.ts
+++ b/src/features/category-acc.directive.ts
@@ -4,6 +4,13 @@ import { map } from 'rxjs/operators';
 import { Feature } from "src/atlasComponents/sapi/sxplrTypes"
 import { ListDirective } from './list/list.directive';
 
+export type GroupedFeature = {
+  features: Feature[]
+  meta: {
+    displayName: string
+  }
+}
+
 @Directive({
   selector: '[sxplrCategoryAcc]',
   exportAs: 'categoryAcc'
@@ -12,7 +19,10 @@ export class CategoryAccDirective implements AfterContentInit, OnDestroy {
 
   public isBusy$ = new BehaviorSubject<boolean>(false)
   public total$ = new BehaviorSubject<number>(0)
-  public features$ = new BehaviorSubject<Feature[]>([])
+  public groupedFeatures$ = new BehaviorSubject<GroupedFeature[]>([])
+  public features$ = this.groupedFeatures$.pipe(
+    map(arr => arr.flatMap(val => val.features))
+  )
 
   @ContentChildren(ListDirective, { read: ListDirective, descendants: true })
   listCmps: QueryList<ListDirective>
@@ -37,10 +47,14 @@ export class CategoryAccDirective implements AfterContentInit, OnDestroy {
 
     const listCmp = Array.from(this.listCmps)
 
-    this.#subscriptions.push( 
+    this.#subscriptions.push(
       combineLatest(
-        listCmp.map(listC => listC.features$)
-      ).subscribe(features => this.features$.next(features.flatMap(f => f))),
+        listCmp.map(
+          listC => listC.features$.pipe(
+            map(features => ({ features, meta: { displayName: listC.displayName } }))
+          )
+        )
+      ).subscribe(val => this.groupedFeatures$.next(val)),
       
       combineLatest(
         listCmp.map(listC => listC.features$)
diff --git a/src/features/entry/entry.flattened.component.html b/src/features/entry/entry.flattened.component.html
index 03bf62d889518945041f00c0965024353e0372e1..db548da3942dcf8a081ed5841bc6fcb31cc4f7ee 100644
--- a/src/features/entry/entry.flattened.component.html
+++ b/src/features/entry/entry.flattened.component.html
@@ -69,6 +69,62 @@
             </mat-panel-description>
         </mat-expansion-panel-header>
 
+
+        <!-- <button mat-button>Show all</button> -->
+        <div class="mat-chip-container"
+            feature-filter-directive
+            [initValue]="true"
+            [items]="categoryAcc.groupedFeatures$ | async "
+            #filterFeatureCls="featureFilterDirective">
+
+            <div class="mat-chip-inner-container">
+
+                <button mat-icon-button matTooltip="Reset filter"
+                    (click)="filterFeatureCls.setAll(true)">
+                    <i class="fas fa-filter"></i>
+                </button>
+
+                <ng-template ngFor [ngForOf]="filterFeatureCls.items" let-grpFeat>
+                    <ng-template [ngIf]="grpFeat.features.length > 0">
+
+                        <ng-template [ngIf]="filterFeatureCls.checked$ | async | grpFeatToName | includes : grpFeat.meta.displayName"
+                            [ngIfThen]="selectedTmpl"
+                            [ngIfElse]="notSelectedTmpl">
+                        </ng-template>
+
+                        <ng-template #textTmpl>
+                            <span>
+                                {{ grpFeat.meta.displayName }}
+                            </span>
+                            <span class="text-muted1">
+                                ({{ grpFeat.features.length }})
+                            </span>
+                        </ng-template>
+                        <ng-template #selectedTmpl>
+                            <button mat-flat-button
+                                (click)="filterFeatureCls.toggle(grpFeat)"
+                                color="primary">
+                                <i class="fas fa-eye"></i>
+                                <ng-template [ngTemplateOutlet]="textTmpl">
+                                </ng-template>
+                            </button>
+                        </ng-template>
+
+                        <ng-template #notSelectedTmpl>
+                            <button mat-flat-button
+                                (click)="filterFeatureCls.toggle(grpFeat)"
+                                color="default">
+                                <i class="fas fa-eye-slash"></i>
+                                <ng-template [ngTemplateOutlet]="textTmpl">
+                                </ng-template>
+                            </button>
+                        </ng-template>
+
+                    </ng-template>
+                </ng-template>
+            </div>
+        </div>
+
         <ng-template ngFor [ngForOf]="keyvalue.value" let-feature>
 
             <div sxplr-feature-list-directive
@@ -78,13 +134,20 @@
                 [bbox]="bbox"
                 [queryParams]="queryParams | mergeObj : { type: (feature.name | featureNamePipe) }"
                 [featureRoute]="feature.path"
+                [name]="feature.name"
+                [displayName]="feature.display_name"
                 #featureListDirective="featureListDirective">
             </div>
         </ng-template>
         
         <cdk-virtual-scroll-viewport itemSize="36"
+            filter-grp-feat
+            [featureDisplayName]="filterFeatureCls.checked$ | async | mapToProperty : 'meta' | mapToProperty : 'displayName'"
+            [groupFeature]="categoryAcc.groupedFeatures$ | async"
+            #filterGrpFeat="filterGrpFeat"
             class="virtual-scroll-viewport">
-            <button *cdkVirtualFor="let feature of categoryAcc.features$ | async"
+
+            <button *cdkVirtualFor="let feature of filterGrpFeat.filteredFeatures$"
                 mat-button
                 class="virtual-scroll-item sxplr-w-100"
                 [matTooltip]="feature.name"
diff --git a/src/features/entry/entry.flattened.component.scss b/src/features/entry/entry.flattened.component.scss
index 6aae997963d51b01cee208293d958dd5fd1591ac..34b69d51fd334765c690052c5676419602215c19 100644
--- a/src/features/entry/entry.flattened.component.scss
+++ b/src/features/entry/entry.flattened.component.scss
@@ -8,4 +8,23 @@ cdk-virtual-scroll-viewport button
     text-align: left;
     height: 36px;
     display: block;
-}
\ No newline at end of file
+}
+
+.mat-chip-container
+{
+    width: 100%;
+    overflow-x: scroll;
+    overflow-y: hidden;
+    padding: 0.5rem;
+}
+
+.mat-chip-inner-container
+{
+    display: inline-flex;
+}
+
+.mat-chip-inner-container button
+{
+    white-space: nowrap;
+    margin: 0.2rem 0.4rem;
+}
diff --git a/src/features/feature-view/feature-view.component.html b/src/features/feature-view/feature-view.component.html
index f4fdfe35f8a3b9f8240413bda9666e322ab06655..3c6339d0eb07bfb052fe578ce2ae2d1d6a5e6492 100644
--- a/src/features/feature-view/feature-view.component.html
+++ b/src/features/feature-view/feature-view.component.html
@@ -33,9 +33,39 @@
       <spinner-cmp></spinner-cmp>
     </ng-template>
 
-    <a mat-icon-button sxplr-hide-when-local *ngFor="let url of feature.link" [href]="url.href" target="_blank">
-      <i class="fas fa-external-link-alt"></i>
-    </a>
+    <!-- template for external link -->
+    <ng-template #externalLinkTmpl let-url>
+      <a mat-icon-button sxplr-hide-when-local [href]="url" target="_blank">
+        <i class="fas fa-external-link-alt"></i>
+      </a>
+    </ng-template>
+
+    <!-- if link is prepopulated -->
+    <ng-template
+      ngFor
+      [ngForOf]="feature.link"
+      let-url>
+      <ng-template
+        [ngTemplateOutlet]="externalLinkTmpl"
+        [ngTemplateOutletContext]="{
+          $implicit: url.href
+        }">
+      </ng-template>
+    </ng-template>
+
+    <!-- if link is lazy fetched -->
+    <ng-template
+      ngFor
+      [ngForOf]="additionalLinks$ | async"
+      let-url>
+      <ng-template
+        [ngTemplateOutlet]="externalLinkTmpl"
+        [ngTemplateOutletContext]="{
+          $implicit: url
+        }">
+      </ng-template>
+    </ng-template>
+
   </mat-card-subtitle>
 </mat-card>
 
diff --git a/src/features/feature-view/feature-view.component.ts b/src/features/feature-view/feature-view.component.ts
index 61371830b8d5e81761b9de75b311523e8016d0b9..b73f0e29cf4edc43b3a75e4385f9e264e2a3a683 100644
--- a/src/features/feature-view/feature-view.component.ts
+++ b/src/features/feature-view/feature-view.component.ts
@@ -1,6 +1,6 @@
 import { ChangeDetectionStrategy, Component, Inject, Input, OnChanges } from '@angular/core';
-import { BehaviorSubject, Observable } from 'rxjs';
-import { filter, map } from 'rxjs/operators';
+import { BehaviorSubject, Observable, Subject } from 'rxjs';
+import { distinctUntilChanged, filter, map } from 'rxjs/operators';
 import { SAPI } from 'src/atlasComponents/sapi/sapi.service';
 import { Feature, TabularFeature, VoiFeature } from 'src/atlasComponents/sapi/sxplrTypes';
 import { DARKTHEME } from 'src/util/injectionTokens';
@@ -28,6 +28,15 @@ export class FeatureViewComponent implements OnChanges {
   @Input()
   feature: Feature
 
+  #detailLinks = new Subject<string[]>()
+  additionalLinks$ = this.#detailLinks.pipe(
+    distinctUntilChanged((o, n) => o.length == n.length),
+    map(links => {
+      const set = new Set((this.feature.link || []).map(v => v.href))
+      return links.filter(l => !set.has(l))
+    })
+  )
+
   busy$ = new BehaviorSubject<boolean>(false)
   
   tabular$ = new BehaviorSubject<TabularFeature<number|string|number[]>>(null)
@@ -90,6 +99,9 @@ export class FeatureViewComponent implements OnChanges {
         if (isVoiData(val)) {
           this.voi$.next(val)
         }
+
+        this.#detailLinks.next((val.link || []).map(l => l.href))
+        
       },
       () => this.busy$.next(false)
     )
diff --git a/src/features/feature.filter.directive.ts b/src/features/feature.filter.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..14421065f2a2ed090a8c31dfef2c41877ddf3152
--- /dev/null
+++ b/src/features/feature.filter.directive.ts
@@ -0,0 +1,95 @@
+import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
+import { BehaviorSubject, combineLatest, concat, merge, of, Subject } from "rxjs";
+import { map, scan, shareReplay, switchMap } from "rxjs/operators";
+
+@Directive({
+  selector: '[feature-filter-directive]',
+  exportAs: 'featureFilterDirective'
+})
+export class FeatureFilterDirective<T> implements OnChanges{
+  @Input()
+  items: T[] = []
+
+  @Input()
+  initValue = false
+
+  #items$ = new BehaviorSubject<T[]>(this.items)
+  #initValue$ = new BehaviorSubject<boolean>(this.initValue)
+  #toggle$ = new Subject<{ target: T }>()
+  #setValue$ = new Subject<{ target: T, flag: boolean}>()
+  #setAll$ = new Subject<{ flag: boolean }>()
+
+  ngOnChanges(changes: SimpleChanges): void {
+    if (changes.items) {
+      this.#items$.next(changes.items.currentValue)
+    }
+    if (changes.initValue) {
+      this.#initValue$.next(changes.initValue.currentValue)
+    }
+  }
+  #checkbox$ = combineLatest([
+    this.#items$,
+    this.#initValue$
+  ]).pipe(
+    switchMap(([items, initFlag]) => {
+      const initialCondition = items.map(item => ({ item, flag: initFlag }))
+      return merge<{ target: T, flag?: boolean, op: string }>(
+        this.#toggle$.pipe(
+          map(v => ({ ...v, op: 'toggle' }))
+        ),
+        this.#setValue$.pipe(
+          map(v => ({ ...v, op: 'set' }))
+        ),
+        this.#setAll$.pipe(
+          map(v => ({ ...v, op: 'setAll' }))
+        ),
+        of({ op: 'noop' })
+      ).pipe(
+        scan((acc, { target, op, flag }) => {
+          
+          if (op === 'noop') return acc
+          if (op === 'setAll') {
+            return acc.map(({ item }) => ({ item, flag }))
+          }
+  
+          const found = acc.find(({ item }) => item === target)
+          const other = acc.filter(({ item }) => item !== target)
+          const itemToAppend = found
+            ? [{
+              item: found.item,
+              flag: op === 'set'
+                ? flag
+                : !found.flag
+            }]
+            : []
+          return [ ...other, ...itemToAppend ]
+        }, initialCondition)
+      )
+    }),
+    shareReplay(1),
+  )
+
+  checked$ = concat(
+    of([] as T[]),
+    this.#checkbox$.pipe(
+      map(arr => arr.filter(v => v.flag).map(v => v.item)),
+    )
+  )
+  
+  unchecked$ = concat(
+    of([] as T[]),
+    this.#checkbox$.pipe(
+      map(arr => arr.filter(v => !v.flag).map(v => v.item)),
+    )
+  )
+
+  toggle(target: T){
+    this.#toggle$.next({ target })
+  }
+  setValue(target: T, flag: boolean) {
+    this.#setValue$.next({ target, flag })
+  }
+  setAll(flag: boolean){
+    this.#setAll$.next({ flag })
+  }
+}
diff --git a/src/features/filterGrpFeat.directive.ts b/src/features/filterGrpFeat.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3caa9416d934aa64a43716dbad8108ee697e698f
--- /dev/null
+++ b/src/features/filterGrpFeat.directive.ts
@@ -0,0 +1,31 @@
+import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
+import { GroupedFeature } from "./category-acc.directive";
+import { combineLatest, Subject } from "rxjs";
+import { map } from "rxjs/operators";
+
+@Directive({
+  selector: '[filter-grp-feat]',
+  exportAs: 'filterGrpFeat'
+})
+export class FilterGroupList implements OnChanges{
+
+  @Input()
+  featureDisplayName: string[] = []
+  #featureDisplayName = new Subject<string[]>()
+
+  @Input()
+  groupFeature: GroupedFeature[] = []
+  #groupFeature = new Subject<GroupedFeature[]>()
+
+  filteredFeatures$ = combineLatest([
+    this.#featureDisplayName,
+    this.#groupFeature
+  ]).pipe(
+    map(([ displaynames, grpfeats ]) => grpfeats.filter(feat => displaynames.includes(feat.meta.displayName)).flatMap(f => f.features))
+  )
+
+  ngOnChanges(): void {
+    this.#featureDisplayName.next(this.featureDisplayName)
+    this.#groupFeature.next(this.groupFeature)
+  }
+}
diff --git a/src/features/grpFeatToName.pipe.ts b/src/features/grpFeatToName.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f124a683609247864bb79b1a55d9055c7b16627d
--- /dev/null
+++ b/src/features/grpFeatToName.pipe.ts
@@ -0,0 +1,13 @@
+import { Pipe, PipeTransform } from "@angular/core";
+import { GroupedFeature } from "./category-acc.directive";
+
+@Pipe({
+  name: 'grpFeatToName',
+  pure: true
+})
+
+export class GroupFeaturesToName implements PipeTransform{
+  public transform(groupFeats: GroupedFeature[]): string[] {
+    return groupFeats.map(f => f.meta.displayName)
+  }
+}
diff --git a/src/features/list/list.directive.ts b/src/features/list/list.directive.ts
index c5c4734d9fdc209219ccd49710f27e15005ffd6f..a2a7353ec31049d15c09b42b7634b94b35110c48 100644
--- a/src/features/list/list.directive.ts
+++ b/src/features/list/list.directive.ts
@@ -12,6 +12,12 @@ import { AllFeatures, FeatureBase } from "../base";
 })
 export class ListDirective extends FeatureBase{
 
+  @Input()
+  name: string
+
+  @Input()
+  displayName: string
+
   @Input()
   featureRoute: string
   private guardedRoute$ = new BehaviorSubject<FeatureType>(null)
diff --git a/src/features/module.ts b/src/features/module.ts
index 48bf3848f516a69cfbb927506318cba85c6b9820..ba78304b9941fd6cafb9c1a85a53f2aa92be54d3 100644
--- a/src/features/module.ts
+++ b/src/features/module.ts
@@ -24,6 +24,10 @@ import { NgLayerCtlModule } from "src/viewerModule/nehuba/ngLayerCtlModule/modul
 import { VoiBboxDirective } from "./voi-bbox.directive";
 import { FilterCategoriesPipe } from "./filterCategories.pipe";
 import { ListDirective } from "./list/list.directive";
+import { MatChipsModule } from "@angular/material/chips";
+import { FeatureFilterDirective } from "./feature.filter.directive";
+import { FilterGroupList } from "./filterGrpFeat.directive"
+import { GroupFeaturesToName } from "./grpFeatToName.pipe";
 
 @NgModule({
   imports: [
@@ -43,6 +47,7 @@ import { ListDirective } from "./list/list.directive";
     MarkdownModule,
     MatTableModule,
     NgLayerCtlModule,
+    MatChipsModule,
   ],
   declarations: [
     EntryComponent,
@@ -50,12 +55,15 @@ import { ListDirective } from "./list/list.directive";
     FeatureViewComponent,
     FilterCategoriesPipe,
     ListDirective,
+    FeatureFilterDirective,
+    FilterGroupList,
 
     CategoryAccDirective,
     VoiBboxDirective,
 
     FeatureNamePipe,
     TransformPdToDsPipe,
+    GroupFeaturesToName,
   ],
   exports: [
     EntryComponent,
diff --git a/src/routerModule/routeStateTransform.service.ts b/src/routerModule/routeStateTransform.service.ts
index deab0f8b9733a703c9279a57c49a299c966a8bce..bbc9c3ab99f3cb27af71e07c49ceb4aa3ca225b4 100644
--- a/src/routerModule/routeStateTransform.service.ts
+++ b/src/routerModule/routeStateTransform.service.ts
@@ -8,7 +8,7 @@ import { atlasSelection, defaultState, MainState, plugins, userInteraction } fro
 import { getParcNgId } from "src/viewerModule/nehuba/config.service";
 import { decodeToNumber, encodeNumber, encodeURIFull, separator } from "./cipher";
 import { TUrlAtlas, TUrlPathObj, TUrlStandaloneVolume } from "./type";
-import { decodePath, encodeId, decodeId, endcodePath } from "./util";
+import { decodePath, encodeId, decodeId, encodePath } from "./util";
 
 @Injectable()
 export class RouteStateTransformSvc {
@@ -210,6 +210,8 @@ export class RouteStateTransformSvc {
     try {
       if (returnObj.f && returnObj.f.length === 1) {
         const decodedFeatId = decodeId(returnObj.f[0])
+          .replace(/~ptc~/g, '://')
+          .replace(/~/g, ':')
         const feature = await this.sapi.getV3FeatureDetailWithId(decodedFeatId).toPromise()
         returnState["[state.userInteraction]"].selectedFeature = feature
       }
@@ -290,7 +292,15 @@ export class RouteStateTransformSvc {
       // nav
       ['@']: cNavString,
       // showing dataset
-      f: selectedFeature && encodeId(selectedFeature.id)
+      f: (() => {
+        return selectedFeature && encodeId(
+          encodeURIFull(
+            selectedFeature.id
+              .replace(/:\/\//, '~ptc~')
+              .replace(/:/g, '~')
+          )
+        )
+      })()
     }
   
     /**
@@ -307,7 +317,7 @@ export class RouteStateTransformSvc {
     const routesArr: string[] = []
     for (const key in routes) {
       if (!!routes[key]) {
-        const segStr = endcodePath(key, routes[key])
+        const segStr = encodePath(key, routes[key])
         routesArr.push(segStr)
       }
     }
diff --git a/src/routerModule/util.ts b/src/routerModule/util.ts
index cd0709ea8fc1a30e4d11eab738db77af0ebd4ad2..0552eb3c882a1bc8e58b151155e5423cba7106e0 100644
--- a/src/routerModule/util.ts
+++ b/src/routerModule/util.ts
@@ -4,7 +4,7 @@ import { Component } from "@angular/core"
 export const encodeId = (id: string) => id && id.replace(/\//g, ':')
 export const decodeId = (codedId: string) => codedId && codedId.replace(/:/g, '/')
 
-export const endcodePath = (key: string, val: string|string[]) =>
+export const encodePath = (key: string, val: string|string[]) =>
   key[0] === '?'
     ? `?${key}=${val}`
     : `${key}:${Array.isArray(val)
@@ -56,7 +56,7 @@ export const encodeCustomState = (key: string, value: string|string[]) => {
     throw new Error(`custom state must start with x-`)
   }
   if (!value) return null
-  return endcodePath(key, value).replace(/\//g, '%2F')
+  return encodePath(key, value).replace(/\//g, '%2F')
 }
 
 @Component({
diff --git a/src/atlasComponents/sapiViews/util/includes.pipe.ts b/src/util/includes.pipe.ts
similarity index 100%
rename from src/atlasComponents/sapiViews/util/includes.pipe.ts
rename to src/util/includes.pipe.ts
diff --git a/src/util/pipes/filterArray.pipe.ts b/src/util/pipes/filterArray.pipe.ts
index 5e7c9653d73430b7631b78cd7a739a2a2ca13c75..3a4f76192591964ce667a568bce41c24635df7fd 100644
--- a/src/util/pipes/filterArray.pipe.ts
+++ b/src/util/pipes/filterArray.pipe.ts
@@ -6,7 +6,7 @@ import { Pipe, PipeTransform } from "@angular/core";
 })
 
 export class FilterArrayPipe implements PipeTransform{
-  public transform<T>(arr: T[], filterFn: (item: T, index: number, array: T[]) => boolean){
+  public transform<T>(arr: T[], filterFn: (item: T, index?: number, array?: T[]) => boolean){
     return (arr || []).filter(filterFn)
   }
 }
diff --git a/src/util/util.module.ts b/src/util/util.module.ts
index b1007281e3c037b4766b301c0189e15dca21a878..de0d23cb14d309d82c2126ebe8b4f2b0421ea9d1 100644
--- a/src/util/util.module.ts
+++ b/src/util/util.module.ts
@@ -1,6 +1,5 @@
 import { NgModule } from "@angular/core";
 import { KeyListner } from "./directives/keyDownListener.directive";
-
 import { StopPropagationDirective } from "./directives/stopPropagation.directive";
 import { SafeResourcePipe } from "./pipes/safeResource.pipe";
 import { CaptureClickListenerDirective } from "./directives/captureClickListener.directive";
@@ -19,6 +18,7 @@ import { DoiParserPipe } from "./pipes/doiPipe.pipe";
 import { GetFilenamePipe } from "./pipes/getFilename.pipe";
 import { CombineFnPipe } from "./pipes/combineFn.pipe";
 import { MergeObjPipe } from "./mergeObj.pipe";
+import { IncludesPipe } from "./includes.pipe";
 
 @NgModule({
   imports:[
@@ -43,6 +43,7 @@ import { MergeObjPipe } from "./mergeObj.pipe";
     GetFilenamePipe,
     CombineFnPipe,
     MergeObjPipe,
+    IncludesPipe,
   ],
   exports: [
     StopPropagationDirective,
@@ -63,6 +64,7 @@ import { MergeObjPipe } from "./mergeObj.pipe";
     GetFilenamePipe,
     CombineFnPipe,
     MergeObjPipe,
+    IncludesPipe,
   ]
 })
 
diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html
index 395ccba4f4f6c16ba74c0b3e215959d1ad7efd0f..1d15fc8f4f9ea9724719939cdd54d7ba4d56135c 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.template.html
+++ b/src/viewerModule/viewerCmp/viewerCmp.template.html
@@ -1010,7 +1010,7 @@
     </ng-template>
   </button>
   <div
-    *ngIf="voiSwitch.switchState$| async"
+    *ngIf="voiSwitch.switchState$ | async"
     voiBbox
     [features]="voiFeatureEntryCmp.features$ | async">