From 5d7c4e75072148e99ef87fa65e1100388cc92a7d Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 28 Jul 2020 15:16:23 +0300 Subject: [PATCH 01/20] feat(core): create multi-tenancy.service --- .../packages/core/src/lib/services/index.ts | 1 + .../src/lib/services/multi-tenancy.service.ts | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index e5e5286710..c084fd4808 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -6,6 +6,7 @@ export * from './dom-insertion.service'; export * from './lazy-load.service'; export * from './list.service'; export * from './localization.service'; +export * from './multi-tenancy.service'; export * from './profile-state.service'; export * from './profile.service'; export * from './rest.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts b/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts new file mode 100644 index 0000000000..3a66a99311 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/multi-tenancy.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { Observable } from 'rxjs'; +import { SetTenant } from '../actions/session.actions'; +import { ABP } from '../models/common'; +import { FindTenantResultDto } from '../models/find-tenant-result-dto'; +import { RestService } from './rest.service'; + +@Injectable({ providedIn: 'root' }) +export class MultiTenancyService { + private _domainTenant: ABP.BasicItem = null; + + set domainTenant(value: ABP.BasicItem) { + this._domainTenant = value; + this.store.dispatch(new SetTenant(value)); + } + + get domainTenant() { + return this._domainTenant; + } + + isTenantBoxVisible = true; + + apiName = 'abp'; + + constructor(private restService: RestService, private store: Store) {} + + findTenantByName(name: string, headers: ABP.Dictionary): Observable { + return this.restService.request( + { + url: `/api/abp/multi-tenancy/tenants/by-name/${name}`, + method: 'GET', + headers, + }, + { apiName: this.apiName }, + ); + } + + findTenantById(id: string, headers: ABP.Dictionary): Observable { + return this.restService.request( + { url: `/api/abp/multi-tenancy/tenants/by-id/${id}`, method: 'GET', headers }, + { apiName: this.apiName }, + ); + } +} From 70308947b6fe45b9f93850f3c7bc86a33096ee77 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 28 Jul 2020 15:16:38 +0300 Subject: [PATCH 02/20] feat: implement multi-tenancy.service to auth-wrapper component --- .../components/auth-wrapper/auth-wrapper.component.html | 2 +- .../lib/components/auth-wrapper/auth-wrapper.component.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html index 3377b74a88..f57643f7b2 100644 --- a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html +++ b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.html @@ -1,6 +1,6 @@
- + diff --git a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts index be35672862..e7b398cc3d 100644 --- a/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/auth-wrapper/auth-wrapper.component.ts @@ -1,4 +1,4 @@ -import { ConfigState, SubscriptionService } from '@abp/ng.core'; +import { ConfigState, SubscriptionService, MultiTenancyService } from '@abp/ng.core'; import { Component, Input, OnInit, TemplateRef } from '@angular/core'; import { Select, Store } from '@ngxs/store'; import { Observable } from 'rxjs'; @@ -26,7 +26,11 @@ export class AuthWrapperComponent tenantBoxKey = eAccountComponents.TenantBox; - constructor(private store: Store, private subscription: SubscriptionService) {} + constructor( + public readonly multiTenancy: MultiTenancyService, + private store: Store, + private subscription: SubscriptionService, + ) {} ngOnInit() { this.subscription.addOne( From 57cd025ba5aab6f5da8f2f4cf7d3a569f57c2f9d Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 28 Jul 2020 15:19:57 +0300 Subject: [PATCH 03/20] feat: add multi-tenancy-utils file --- .../packages/core/src/lib/core.module.ts | 4 +- .../packages/core/src/lib/models/config.ts | 1 + .../src/lib/models/find-tenant-result-dto.ts | 16 ++ .../packages/core/src/lib/models/index.ts | 1 + .../utils/formatted-string-value-extractor.ts | 156 ++++++++++++++++++ .../packages/core/src/lib/utils/index.ts | 1 + .../core/src/lib/utils/initial-utils.ts | 5 +- .../core/src/lib/utils/multi-tenancy-utils.ts | 73 ++++++++ 8 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts create mode 100644 npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts create mode 100644 npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 3fd29fec53..16295b5abf 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -34,10 +34,10 @@ import { ConfigState } from './states/config.state'; import { ProfileState } from './states/profile.state'; import { ReplaceableComponentsState } from './states/replaceable-components.state'; import { SessionState } from './states/session.state'; -import { CORE_OPTIONS, coreOptionsFactory } from './tokens/options.token'; +import { coreOptionsFactory, CORE_OPTIONS } from './tokens/options.token'; import { noop } from './utils/common-utils'; import './utils/date-extensions'; -import { getInitialData, localeInitializer, configureOAuth } from './utils/initial-utils'; +import { configureOAuth, getInitialData, localeInitializer } from './utils/initial-utils'; export function storageFactory(): OAuthStorage { return localStorage; diff --git a/npm/ng-packs/packages/core/src/lib/models/config.ts b/npm/ng-packs/packages/core/src/lib/models/config.ts index d328cfe5b5..682e49e94e 100644 --- a/npm/ng-packs/packages/core/src/lib/models/config.ts +++ b/npm/ng-packs/packages/core/src/lib/models/config.ts @@ -17,6 +17,7 @@ export namespace Config { export interface Application { name: string; + baseUrl?: string; logoUrl?: string; } diff --git a/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts b/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts new file mode 100644 index 0000000000..751a9dc87a --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts @@ -0,0 +1,16 @@ + +export class FindTenantResultDto { + success: boolean; + tenantId?: string; + name: string; + + constructor(initialValues: Partial = {}) { + if (initialValues) { + for (const key in initialValues) { + if (initialValues.hasOwnProperty(key)) { + this[key] = initialValues[key]; + } + } + } + } +} diff --git a/npm/ng-packs/packages/core/src/lib/models/index.ts b/npm/ng-packs/packages/core/src/lib/models/index.ts index c0950c3dee..e5776a682e 100644 --- a/npm/ng-packs/packages/core/src/lib/models/index.ts +++ b/npm/ng-packs/packages/core/src/lib/models/index.ts @@ -2,6 +2,7 @@ export * from './application-configuration'; export * from './common'; export * from './config'; export * from './dtos'; +export * from './find-tenant-result-dto'; export * from './profile'; export * from './replaceable-components'; export * from './rest'; diff --git a/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts b/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts new file mode 100644 index 0000000000..7e9e3f00da --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts @@ -0,0 +1,156 @@ +class ExtractionResult { + public isMatch: boolean; + public matches: any[]; + + constructor(isMatch: boolean) { + this.isMatch = isMatch; + this.matches = []; + } +} + +enum FormatStringTokenType { + ConstantText, + DynamicValue, +} + +class FormatStringToken { + public text: string; + public type: FormatStringTokenType; + + constructor(text: string, type: FormatStringTokenType) { + this.text = text; + this.type = type; + } +} + +class FormatStringTokenizer { + tokenize(format: string, includeBracketsForDynamicValues: boolean = false): FormatStringToken[] { + const tokens: FormatStringToken[] = []; + + let currentText = ''; + let inDynamicValue = false; + + for (let i = 0; i < format.length; i++) { + const c = format[i]; + switch (c) { + case '{': + if (inDynamicValue) { + throw new Error( + 'Incorrect syntax at char ' + + i + + '! format string can not contain nested dynamic value expression!', + ); + } + + inDynamicValue = true; + + if (currentText.length > 0) { + tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); + currentText = ''; + } + + break; + case '}': + if (!inDynamicValue) { + throw new Error( + 'Incorrect syntax at char ' + + i + + '! These is no opening brackets for the closing bracket }.', + ); + } + + inDynamicValue = false; + + if (currentText.length <= 0) { + throw new Error( + 'Incorrect syntax at char ' + i + '! Brackets does not containt any chars.', + ); + } + + let dynamicValue = currentText; + if (includeBracketsForDynamicValues) { + dynamicValue = '{' + dynamicValue + '}'; + } + + tokens.push(new FormatStringToken(dynamicValue, FormatStringTokenType.DynamicValue)); + currentText = ''; + + break; + default: + currentText += c; + break; + } + } + + if (inDynamicValue) { + throw new Error('There is no closing } char for an opened { char.'); + } + + if (currentText.length > 0) { + tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); + } + + return tokens; + } +} + +export class FormattedStringValueExtractor { + extract(str: string, format: string): ExtractionResult { + if (str === format) { + return new ExtractionResult(true); + } + + const formatTokens = new FormatStringTokenizer().tokenize(format); + if (!formatTokens) { + return new ExtractionResult(str === ''); + } + + const result = new ExtractionResult(true); + + for (let i = 0; i < formatTokens.length; i++) { + const currentToken = formatTokens[i]; + const previousToken = i > 0 ? formatTokens[i - 1] : null; + + if (currentToken.type === FormatStringTokenType.ConstantText) { + if (i === 0) { + if (str.indexOf(currentToken.text) !== 0) { + result.isMatch = false; + return result; + } + + str = str.substr(currentToken.text.length, str.length - currentToken.text.length); + } else { + const matchIndex = str.indexOf(currentToken.text); + if (matchIndex < 0) { + result.isMatch = false; + return result; + } + + result.matches.push({ name: previousToken.text, value: str.substr(0, matchIndex) }); + str = str.substring(0, matchIndex + currentToken.text.length); + } + } + } + + const lastToken = formatTokens[formatTokens.length - 1]; + if (lastToken.type === FormatStringTokenType.DynamicValue) { + result.matches.push({ name: lastToken.text, value: str }); + } + + return result; + } + + isMatch(str: string, format: string): string[] { + const result = new FormattedStringValueExtractor().extract(str, format); + if (!result.isMatch) { + return []; + } + + const values = []; + for (let i = 0; i < result.matches.length; i++) { + values.push(result.matches[i].value); + } + + return values; + } +} diff --git a/npm/ng-packs/packages/core/src/lib/utils/index.ts b/npm/ng-packs/packages/core/src/lib/utils/index.ts index 6f6136b195..b31c0320f1 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/index.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/index.ts @@ -9,4 +9,5 @@ export * from './localization-utils'; export * from './number-utils'; export * from './route-utils'; export * from './rxjs-utils'; +export * from './multi-tenancy-utils'; export * from './tree-utils'; diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index 78677b7ca4..bca8e1e176 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -7,6 +7,7 @@ import { GetAppConfiguration } from '../actions/config.actions'; import { ABP } from '../models/common'; import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens/options.token'; +import { parseTenantFromUrl } from './multi-tenancy-utils'; export function configureOAuth(injector: Injector, options: ABP.Root) { const fn = () => { @@ -19,10 +20,12 @@ export function configureOAuth(injector: Injector, options: ABP.Root) { } export function getInitialData(injector: Injector) { - const fn = () => { + const fn = async () => { const store: Store = injector.get(Store); const { skipGetAppConfiguration } = injector.get(CORE_OPTIONS) as ABP.Root; + await parseTenantFromUrl(injector); + if (skipGetAppConfiguration) return; return store diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts new file mode 100644 index 0000000000..237b4b5501 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -0,0 +1,73 @@ +import { Injector } from '@angular/core'; +import { Store } from '@ngxs/store'; +import { ConfigState } from '../states/config.state'; +import { Config } from '../models/config'; +import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; +import { MultiTenancyService } from '../services/multi-tenancy.service'; +import { tap, switchMap } from 'rxjs/operators'; +import { SetTenant, SetEnvironment } from '../actions'; +import { of } from 'rxjs'; + +const tenancyPlaceholder = '{TENANCY_NAME}'; + +export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { + if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; + + const currentRootAddress = document.location.href; + + const formattedStringValueExtracter = new FormattedStringValueExtractor(); + const values: any[] = formattedStringValueExtracter.isMatch(currentRootAddress, appBaseUrl); + if (!values.length) { + return null; + } + + return values[0]; +} + +export async function parseTenantFromUrl(injector: Injector) { + const store: Store = injector.get(Store); + const multiTenancyService = injector.get(MultiTenancyService); + const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; + + const { baseUrl = '' } = environment.application; + const tenancyName = getCurrentTenancyNameOrNull(baseUrl); + + if (tenancyName) { + multiTenancyService.isTenantBoxVisible = false; + + return setEnvironment(store, tenancyName) + .pipe( + switchMap(() => multiTenancyService.findTenantByName(tenancyName, { __tenant: '' })), + tap(res => { + if (!res.success) return; + const tenant = { id: res.tenantId, name: res.name }; + multiTenancyService.domainTenant = tenant; + }), + ) + .toPromise(); + } + + return Promise.resolve(); +} + +export function setEnvironment(store: Store, tenancyName: string) { + const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; + + if (environment.application.baseUrl) { + environment.application.baseUrl = environment.application.baseUrl.replace( + tenancyPlaceholder, + tenancyName, + ); + } + + Object.keys(environment.apis).forEach(api => { + Object.keys(environment.apis[api]).forEach(key => { + environment.apis[api][key] = environment.apis[api][key].replace( + tenancyPlaceholder, + tenancyName, + ); + }); + }); + + return store.dispatch(new SetEnvironment(environment)); +} From 532645a36706f34ac8b5b7f4096217a60fb17078 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 08:51:16 +0300 Subject: [PATCH 04/20] feat: set oAuth configuration when dispatched the SetEnvironment action --- .../core/src/lib/states/config.state.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 713eb336e1..1134c85bce 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -10,6 +10,9 @@ import { SetLanguage } from '../actions/session.actions'; import { ApplicationConfiguration } from '../models/application-configuration'; import { Config } from '../models/config'; import { SessionState } from './session.state'; +import compare from 'just-compare'; +import clone from 'just-clone'; +import { OAuthService } from 'angular-oauth2-oidc'; @State({ name: 'ConfigState', @@ -29,7 +32,7 @@ export class ConfigState { static getOne(key: string) { const selector = createSelector([ConfigState], (state: Config.State) => { - return state[key]; + return clone(state[key]); }); return selector; @@ -194,7 +197,7 @@ export class ConfigState { return selector; } - constructor(private http: HttpClient, private store: Store) {} + constructor(private http: HttpClient, private store: Store, private oAuthService: OAuthService) {} @Action(GetAppConfiguration) addData({ patchState, dispatch }: StateContext) { @@ -232,7 +235,16 @@ export class ConfigState { } @Action(SetEnvironment) - setEnvironment({ patchState }: StateContext, { environment }: SetEnvironment) { + setEnvironment( + { getState, patchState }: StateContext, + { environment }: SetEnvironment, + ) { + const { oAuthConfig } = getState().environment; + + if (!compare(oAuthConfig, environment.oAuthConfig)) { + this.oAuthService.configure(environment.oAuthConfig); + } + return patchState({ environment, }); From 8fe5c4e48717ab4dc0e5c63d31ebe6b5e1b83de8 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 08:55:05 +0300 Subject: [PATCH 05/20] chore: add environment types --- .../apps/dev-app/src/environments/environment.prod.ts | 6 ++++-- npm/ng-packs/apps/dev-app/src/environments/environment.ts | 6 ++++-- templates/app/angular/src/environments/environment.prod.ts | 6 ++++-- templates/app/angular/src/environments/environment.ts | 5 ++++- .../projects/dev-app/src/environments/environment.prod.ts | 6 ++++-- .../projects/dev-app/src/environments/environment.ts | 6 ++++-- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/npm/ng-packs/apps/dev-app/src/environments/environment.prod.ts b/npm/ng-packs/apps/dev-app/src/environments/environment.prod.ts index ae0e6aba2c..21e1302773 100644 --- a/npm/ng-packs/apps/dev-app/src/environments/environment.prod.ts +++ b/npm/ng-packs/apps/dev-app/src/environments/environment.prod.ts @@ -1,7 +1,10 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: true, hmr: false, application: { + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -10,7 +13,6 @@ export const environment = { clientId: 'MyProjectName_App', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', - showDebugInformation: true, oidc: false, requireHttps: true, }, @@ -19,4 +21,4 @@ export const environment = { url: 'https://localhost:44305', }, }, -}; +} as Config.Environment; diff --git a/npm/ng-packs/apps/dev-app/src/environments/environment.ts b/npm/ng-packs/apps/dev-app/src/environments/environment.ts index e678b55a74..8cae243d46 100644 --- a/npm/ng-packs/apps/dev-app/src/environments/environment.ts +++ b/npm/ng-packs/apps/dev-app/src/environments/environment.ts @@ -1,7 +1,10 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: false, hmr: false, application: { + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -10,7 +13,6 @@ export const environment = { clientId: 'MyProjectName_App', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', - showDebugInformation: true, oidc: false, requireHttps: true, }, @@ -19,4 +21,4 @@ export const environment = { url: 'https://localhost:44305', }, }, -}; +} as Config.Environment; diff --git a/templates/app/angular/src/environments/environment.prod.ts b/templates/app/angular/src/environments/environment.prod.ts index 53f0ecdf89..b5e65817d2 100644 --- a/templates/app/angular/src/environments/environment.prod.ts +++ b/templates/app/angular/src/environments/environment.prod.ts @@ -1,6 +1,9 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: true, application: { + baseUrl: 'https://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -9,7 +12,6 @@ export const environment = { clientId: 'MyProjectName_App', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', - showDebugInformation: true, oidc: false, requireHttps: true, }, @@ -21,4 +23,4 @@ export const environment = { localization: { defaultResourceName: 'MyProjectName', }, -}; +} as Config.Environment; diff --git a/templates/app/angular/src/environments/environment.ts b/templates/app/angular/src/environments/environment.ts index d5d0dff39e..2039e8a2dc 100644 --- a/templates/app/angular/src/environments/environment.ts +++ b/templates/app/angular/src/environments/environment.ts @@ -1,6 +1,9 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: false, application: { + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -21,4 +24,4 @@ export const environment = { localization: { defaultResourceName: 'MyProjectName', }, -}; +} as Config.Environment; diff --git a/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts b/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts index 9171185a9e..403476b62c 100644 --- a/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts +++ b/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts @@ -1,6 +1,9 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: true, application: { + baseUrl: 'https://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -9,7 +12,6 @@ export const environment = { clientId: 'MyProjectName_ConsoleTestApp', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', - showDebugInformation: true, oidc: false, requireHttps: true, }, @@ -21,4 +23,4 @@ export const environment = { url: 'https://localhost:44300', }, }, -}; +} as Config.Environment; diff --git a/templates/module/angular/projects/dev-app/src/environments/environment.ts b/templates/module/angular/projects/dev-app/src/environments/environment.ts index 452b154f4a..4102abb202 100644 --- a/templates/module/angular/projects/dev-app/src/environments/environment.ts +++ b/templates/module/angular/projects/dev-app/src/environments/environment.ts @@ -1,6 +1,9 @@ +import { Config } from '@abp/ng.core'; + export const environment = { production: false, application: { + baseUrl: 'https://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, @@ -9,7 +12,6 @@ export const environment = { clientId: 'MyProjectName_ConsoleTestApp', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', - showDebugInformation: true, oidc: false, requireHttps: true, }, @@ -21,4 +23,4 @@ export const environment = { url: 'https://localhost:44300', }, }, -}; +} as Config.Environment; From 9a9d0b6484404f859f031c41c4affe24791f866e Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 08:56:26 +0300 Subject: [PATCH 06/20] test: add multi-tenancy-utils.spec.ts --- .../src/lib/tests/multi-tenancy-utils.spec.ts | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts diff --git a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts new file mode 100644 index 0000000000..0784583704 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts @@ -0,0 +1,117 @@ +import { Component, Injector } from '@angular/core'; +import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; +import { Store } from '@ngxs/store'; +import { MultiTenancyService } from '../services/multi-tenancy.service'; +import { parseTenantFromUrl, getCurrentTenancyNameOrNull } from '../utils'; +import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; +import { of, Subject, BehaviorSubject } from 'rxjs'; +import { FindTenantResultDto } from '../models/find-tenant-result-dto'; +import clone from 'just-clone'; + +const environment = { + production: false, + hmr: false, + application: { + baseUrl: 'https://{TENANCY_NAME}.volosoft.com', + name: 'MyProjectName', + logoUrl: '', + }, + oAuthConfig: { + issuer: 'https://{TENANCY_NAME}.api.volosoft.com', + clientId: 'MyProjectName_App', + dummyClientSecret: '1q2w3e*', + scope: 'MyProjectName', + oidc: false, + requireHttps: true, + }, + apis: { + default: { + url: 'https://{TENANCY_NAME}.api.volosoft.com', + }, + abp: { + url: 'https://api.volosoft.com/{TENANCY_NAME}', + }, + }, +}; + +const setHref = url => { + global.window = Object.create(window); + delete window.location; + Object.defineProperty(window, 'location', { + value: { + href: url, + }, + }); +}; + +@Component({ + selector: 'abp-dummy', + template: '', +}) +export class DummyComponent {} + +describe('MultiTenancyUtils', () => { + let spectator: Spectator; + const createComponent = createComponentFactory({ + component: DummyComponent, + mocks: [Store, MultiTenancyService], + }); + + beforeEach(() => (spectator = createComponent())); + + describe('#getCurrentTenancyNameOrNull', () => { + test('should get tenancy name from href', async () => { + setHref('https://abp.volosoft.com/'); + expect(getCurrentTenancyNameOrNull('https://{TENANCY_NAME}.volosoft.com')).toBe('abp'); + + setHref('https://volosoft.com/'); + expect(getCurrentTenancyNameOrNull('https://{TENANCY_NAME}.com')).toBe('volosoft'); + + setHref('https://volosoft.com/abp/'); + expect(getCurrentTenancyNameOrNull('https://volosoft.com/{TENANCY_NAME}')).toBe('abp'); + }); + }); + + describe('#parseTenantFromUrl', () => { + test('should get the tenancyName, set replaced environment and call the findTenantByName method of MultiTenancyService', async () => { + const injector = spectator.inject(Injector); + const injectorSpy = jest.spyOn(injector, 'get'); + const store = spectator.inject(Store); + const selectSnapshotSpy = jest.spyOn(store, 'selectSnapshot'); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const multiTenancyService = spectator.inject(MultiTenancyService); + const findTenantByNameSpy = jest.spyOn(multiTenancyService, 'findTenantByName'); + + injectorSpy.mockReturnValueOnce(spectator.inject(Store)); + injectorSpy.mockReturnValueOnce(multiTenancyService); + selectSnapshotSpy.mockReturnValue(clone(environment)); + + setHref('https://abp.volosoft.com/'); + + dispatchSpy.mockReturnValue(new BehaviorSubject(true)); + findTenantByNameSpy.mockReturnValue( + new BehaviorSubject({ name: 'abp', tenantId: '1', success: true } as FindTenantResultDto), + ); + + parseTenantFromUrl(injector); + + const replacedEnv = { + ...environment, + application: { ...environment.application, baseUrl: 'https://abp.volosoft.com' }, + oAuthConfig: { ...environment.oAuthConfig, issuer: 'https://abp.api.volosoft.com' }, + apis: { + default: { + url: 'https://abp.api.volosoft.com', + }, + abp: { + url: 'https://api.volosoft.com/abp', + }, + }, + }; + + expect(dispatchSpy).toHaveBeenCalledWith({ environment: replacedEnv }); + expect(findTenantByNameSpy).toHaveBeenCalledWith('abp', { __tenant: '' }); + expect(multiTenancyService.domainTenant).toEqual({ id: '1', name: 'abp' }); + }); + }); +}); From 42ace83cef2080734060c405eda0358958f6bb97 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 08:56:54 +0300 Subject: [PATCH 07/20] test: fix testing errors --- .../core/src/lib/tests/config.state.spec.ts | 5 +++-- .../core/src/lib/tests/initial-utils.spec.ts | 19 +++++++++++-------- .../core/src/lib/tests/rest.service.spec.ts | 2 ++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts index e30a55635b..7ad22f8ab6 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts @@ -6,6 +6,7 @@ import { SetLanguage } from '../actions'; import { Config } from '../models/config'; import { ApplicationConfigurationService, ConfigStateService } from '../services'; import { ConfigState } from '../states'; +import { OAuthService } from 'angular-oauth2-oidc'; export const CONFIG_STATE_DATA = { environment: { @@ -107,14 +108,14 @@ describe('ConfigState', () => { const createService = createServiceFactory({ service: ConfigStateService, - mocks: [ApplicationConfigurationService, Store, HttpClient], + mocks: [ApplicationConfigurationService, Store, HttpClient, OAuthService], }); beforeEach(() => { spectator = createService(); store = spectator.inject(Store); service = spectator.service; - state = new ConfigState(spectator.inject(HttpClient), store); + state = new ConfigState(spectator.inject(HttpClient), store, spectator.inject(OAuthService)); }); describe('#getAll', () => { diff --git a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts index 9a4166e7cc..f1417eae2f 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts @@ -3,8 +3,9 @@ import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; import { of } from 'rxjs'; import { GetAppConfiguration } from '../actions'; -import { getInitialData, localeInitializer, configureOAuth } from '../utils'; +import { getInitialData, localeInitializer, configureOAuth, checkAccessToken } from '../utils'; import { OAuthService } from 'angular-oauth2-oidc'; +import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; @Component({ selector: 'abp-dummy', @@ -41,6 +42,8 @@ describe('InitialUtils', () => { const injectorSpy = jest.spyOn(injector, 'get'); const store = spectator.inject(Store); const dispatchSpy = jest.spyOn(store, 'dispatch'); + const parseTenantFromUrlSpy = jest.spyOn(multiTenancyUtils, 'parseTenantFromUrl'); + parseTenantFromUrlSpy.mockReturnValue(Promise.resolve()); injectorSpy.mockReturnValueOnce(store); injectorSpy.mockReturnValueOnce({ skipGetAppConfiguration: false }); @@ -57,16 +60,16 @@ describe('InitialUtils', () => { test('should call logOut fn of OAuthService when token is valid and current user not found', async () => { const injector = spectator.inject(Injector); const injectorSpy = jest.spyOn(injector, 'get'); - const store = spectator.inject(Store); - const dispatchSpy = jest.spyOn(store, 'dispatch'); const logOutFn = jest.fn(); - injectorSpy.mockReturnValueOnce(store); - injectorSpy.mockReturnValueOnce({ skipGetAppConfiguration: false }); - injectorSpy.mockReturnValueOnce({ hasValidAccessToken: () => true, logOut: logOutFn }); - dispatchSpy.mockReturnValue(of({ currentUser: { id: null } })); + injectorSpy.mockReturnValue({ hasValidAccessToken: () => true, logOut: logOutFn }); - getInitialData(injector)(); + checkAccessToken( + { + selectSnapshot: () => false, + } as any, + injector, + ); expect(logOutFn).toHaveBeenCalled(); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts index 601c9dd6d2..ee9f07f5a8 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts @@ -6,6 +6,7 @@ import { Rest } from '../models'; import { RestService } from '../services/rest.service'; import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens'; +import { OAuthService } from 'angular-oauth2-oidc'; describe('HttpClient testing', () => { let spectator: SpectatorHttp; @@ -16,6 +17,7 @@ describe('HttpClient testing', () => { dataService: RestService, imports: [NgxsModule.forRoot([ConfigState])], providers: [{ provide: CORE_OPTIONS, useValue: { environment: {} } }], + mocks: [OAuthService], }); beforeEach(() => { From b29460fcdc2b8bf550c7a9da499d45d37f5d2a98 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 08:57:54 +0300 Subject: [PATCH 08/20] feat: replace oAuth issuer --- .../core/src/lib/utils/initial-utils.ts | 2 +- .../core/src/lib/utils/multi-tenancy-utils.ts | 28 ++++--- .../extensions/src/tests/state.util.spec.ts | 3 +- .../src/lib/tests/validation-utils.spec.ts | 3 +- npm/ng-packs/yarn.lock | 82 +++++++++---------- 5 files changed, 63 insertions(+), 55 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index bca8e1e176..d9c8ae163b 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -37,7 +37,7 @@ export function getInitialData(injector: Injector) { return fn; } -function checkAccessToken(store: Store, injector: Injector) { +export function checkAccessToken(store: Store, injector: Injector) { const oAuth = injector.get(OAuthService); if (oAuth.hasValidAccessToken() && !store.selectSnapshot(ConfigState.getDeep('currentUser.id'))) { oAuth.logOut(); diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 237b4b5501..2d96c833c6 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -1,22 +1,23 @@ import { Injector } from '@angular/core'; import { Store } from '@ngxs/store'; -import { ConfigState } from '../states/config.state'; +import { switchMap, tap } from 'rxjs/operators'; +import { SetEnvironment } from '../actions'; import { Config } from '../models/config'; -import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; import { MultiTenancyService } from '../services/multi-tenancy.service'; -import { tap, switchMap } from 'rxjs/operators'; -import { SetTenant, SetEnvironment } from '../actions'; -import { of } from 'rxjs'; +import { ConfigState } from '../states/config.state'; +import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; const tenancyPlaceholder = '{TENANCY_NAME}'; export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; - const currentRootAddress = document.location.href; + if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; + + const currentRootAddress = window.location.href; - const formattedStringValueExtracter = new FormattedStringValueExtractor(); - const values: any[] = formattedStringValueExtracter.isMatch(currentRootAddress, appBaseUrl); + const formattedStringValueExtractor = new FormattedStringValueExtractor(); + const values = formattedStringValueExtractor.isMatch(currentRootAddress, appBaseUrl); if (!values.length) { return null; } @@ -39,9 +40,9 @@ export async function parseTenantFromUrl(injector: Injector) { .pipe( switchMap(() => multiTenancyService.findTenantByName(tenancyName, { __tenant: '' })), tap(res => { - if (!res.success) return; - const tenant = { id: res.tenantId, name: res.name }; - multiTenancyService.domainTenant = tenant; + multiTenancyService.domainTenant = res.success + ? { id: res.tenantId, name: res.name } + : null; }), ) .toPromise(); @@ -60,6 +61,11 @@ export function setEnvironment(store: Store, tenancyName: string) { ); } + environment.oAuthConfig.issuer = environment.oAuthConfig.issuer.replace( + tenancyPlaceholder, + tenancyName, + ); + Object.keys(environment.apis).forEach(api => { Object.keys(environment.apis[api]).forEach(key => { environment.apis[api][key] = environment.apis[api][key].replace( diff --git a/npm/ng-packs/packages/theme-shared/extensions/src/tests/state.util.spec.ts b/npm/ng-packs/packages/theme-shared/extensions/src/tests/state.util.spec.ts index 9592d4c9c1..86060b8597 100644 --- a/npm/ng-packs/packages/theme-shared/extensions/src/tests/state.util.spec.ts +++ b/npm/ng-packs/packages/theme-shared/extensions/src/tests/state.util.spec.ts @@ -13,6 +13,7 @@ import { getObjectExtensionEntitiesFromStore, mapEntitiesToContributors, } from '../lib/utils/state.util'; +import { OAuthService } from 'angular-oauth2-oidc'; describe('State Utils', () => { let spectator: SpectatorService; @@ -21,7 +22,7 @@ describe('State Utils', () => { const createService = createServiceFactory({ service: Store, imports: [NgxsModule.forRoot([ConfigState])], - mocks: [HttpClient], + mocks: [HttpClient, OAuthService], }); beforeEach(() => { diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts b/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts index 35a46e1ae9..22f445c36c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tests/validation-utils.spec.ts @@ -6,6 +6,7 @@ import { NgxsModule, Store } from '@ngxs/store'; import { HttpClient } from '@angular/common/http'; import { getPasswordValidators } from '../utils'; import { Validators } from '@angular/forms'; +import { OAuthService } from 'angular-oauth2-oidc'; @Component({ template: '', selector: 'abp-dummy' }) class DummyComponent {} @@ -15,7 +16,7 @@ describe('ValidationUtils', () => { const createComponent = createComponentFactory({ component: DummyComponent, imports: [NgxsModule.forRoot([ConfigState]), NgxValidateCoreModule.forRoot()], - mocks: [HttpClient], + mocks: [HttpClient, OAuthService], }); beforeEach(() => (spectator = createComponent())); diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index c00ccb0da6..0f72400c00 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -280,9 +280,9 @@ rxjs "6.4.0" "@angular/animations@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-10.0.5.tgz#41c1419f5233cf8adc2139461a552969e1f938c1" - integrity sha512-vHWn7NJiiDAok36GSBJ0y/nqjd4UFl9WGIEsvydUqnyBJ0scuqJa+hADrWwqkK7b/xVW9ARVG00NXmemEPUVGA== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-10.0.6.tgz#ab1d7dd5c7a76da2528a705f5186733763eee545" + integrity sha512-D2cDrfwnVjL0/6m1v35mAYebH2z0I3WJXohhePaDHEKBEXfXpBIbqqSiRpV9jLSa/xgmJPh4FSNVDCmKmuEmfg== dependencies: tslib "^2.0.0" @@ -320,9 +320,9 @@ uuid "8.1.0" "@angular/common@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-10.0.5.tgz#f1c1b8671dbacc263d5d4f63606a82bc968644ff" - integrity sha512-AKmD/X13q3zzo5uTV/M4dWpAqJ136187rL4VweRc6b5t/oZ3VGcejjElZebgtoyGTye8luIP6fZ/LMb580lBlQ== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-10.0.6.tgz#c279d771eef1e623bd8336c70c3ee821bbebbdd4" + integrity sha512-xS9IJGg6s+Y3K7pe9Oz39Dnpq5uSuUj3HkLKt1db5vPPAeT1qdZ+rdH5hnGwbf8Ihd6ZQacTAlh9W6MnqorZ0w== dependencies: tslib "^2.0.0" @@ -353,28 +353,28 @@ tslib "^2.0.0" "@angular/core@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-10.0.5.tgz#52a11d1b6ce065f6c26d919ab3bea233f51902be" - integrity sha512-zoIxIi/UaRImeC1uD+eIKrdcihvQR/zfbqKgK67IPy/tghijxge1Tbl8FWIAT0ncAj0XH/JHsWnVdUV/TUI+CA== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-10.0.6.tgz#91feaa070a65db22cf8eb65523351b653ce80d2a" + integrity sha512-mk/7XmZg7EeWEgl2UEyhyU6eukm2h+Thw1Ue84aBxMDaqt1RUpsPwpGCfIRfzH9gdzAjJUAPxiHAN2CF+3Wohw== dependencies: tslib "^2.0.0" "@angular/forms@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-10.0.5.tgz#c1e3d7218770e56ab0060b28dbf33d76a481a1c5" - integrity sha512-Bv+KEPjqd+ndl/Z0w1uWsBmvb8Je1JObHRjbKAcW7c4r1CVobm+QJv6r6MDL+FOs78lnrm8baekGLQyHH1uO7g== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-10.0.6.tgz#5c98f7ef95f716986968a51946a7b1b9e6e36d40" + integrity sha512-C/+o4lLqyE2QX1brNBxf5yqBPxNpfRA8Rv0Nb1nQE0T6Y/AjyQWxYYl34fD6zk1WQfP3X8bUgkbhHhefmjVZKw== dependencies: tslib "^2.0.0" "@angular/language-service@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-10.0.5.tgz#2e4b24f7440257d3038ad717b19c5c0065684937" - integrity sha512-WJz5+XxOb0ORUERwNEUsX+0L7V4Tm7tz6i/mKAcz5SbE5eVfi+ywT+Zg7xMVRhyEpwDycqLXHK4piBOuGIjk+g== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-10.0.6.tgz#d76e8f1850e521f716c15755b869ea4e49b8c59d" + integrity sha512-Aaee3kjmIPnTQJZL1+eBgkP+bnNh9zj6F78WEoYX7lHt98uRBfv3C9Wl+S4Gewoe99d7BZ53JdthsKY+ejCSIA== "@angular/localize@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-10.0.5.tgz#cc51976e0ad3cdd05df0ce8448b85d1f2b9ff492" - integrity sha512-iyZ58H7+WBm9J1K2OLKgFFHno33KOu1FMQKaGdj/XCZaG1PphanOUivNxvxXo/6r71UW6uX/U17Rk//F8M0zPA== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-10.0.6.tgz#da109c374da8576fe48ab13d3487bf33be65c03f" + integrity sha512-wcdPphTnBisN6kE37lilt4U7yJKKoM8NKz7hpSq8KTBvf0LN4AfYDzkIJbuapKeolQavblIKgAwkXzsjBhBa2A== dependencies: "@babel/core" "7.8.3" glob "7.1.2" @@ -390,23 +390,23 @@ yargs "15.3.0" "@angular/platform-browser-dynamic@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.5.tgz#bf0e6af90677e08c38747b1d1b9bacb2463872e0" - integrity sha512-Qa6RM9aJuuw5E7BeGBG9/kCOtssI6Wyzbb/8awzZFF6Fjqom1kef185nwx7SgQs2cdrhqRAgjt0eDJqTfSVb+Q== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.6.tgz#664424e27a38dc599bf6003284ca3938f1450b32" + integrity sha512-ao6i9mEy314SI9Z57JPyKvb4sF61i2RNKHN/XuTpPBIRJ8ryOhG6aS1kN2gNFfj8HmyxZS0zohxTxd+nGitGgw== dependencies: tslib "^2.0.0" "@angular/platform-browser@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-10.0.5.tgz#0b90263a3858385cfb3ab440358d19eb9e8e91d3" - integrity sha512-bmknyK18yMv+iLCqcrfcpq3/2Ls9mRA1lOe7YhSGpHxM969Rb6Av8vJNW+uv0y7+gTvxacmpiQO8iryr/xvzRg== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-10.0.6.tgz#1a48add3a697105ea5f1bc1e72bb6336c4832dbf" + integrity sha512-i3jqfXK6ZNwCJbCadeUC+ZAGvXZ0/k7/LocxKACFQW4a5o1W8aACn8COYDvdKMsT1B+tM9Wv1nDh3qjPZthaXw== dependencies: tslib "^2.0.0" "@angular/router@~10.0.0": - version "10.0.5" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-10.0.5.tgz#3e5f8be439b827b1d7bc980d673dec216a2f0769" - integrity sha512-hUGffVOjkdaN5IN9fSipm5ED+XGyfc9yOr5hYr/6YA3H4xaQzXZGlzrrDhAVltTyYalD2LJeXhzlvp59lXgcjg== + version "10.0.6" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-10.0.6.tgz#c1e7a6b6a5472baa345fea8f472e9e9a7ef20c3c" + integrity sha512-+5c/1KitUeMHd7FPAKJ25aloouFHEjlPe5KKGJFtkuzZ7SOi3zwF3ASR52ysnGs/YymdBakIY8kg1Do00xn2wA== dependencies: tslib "^2.0.0" @@ -2735,9 +2735,9 @@ integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= "@types/node@*", "@types/node@>= 8": - version "14.0.26" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.26.tgz#22a3b8a46510da8944b67bfc27df02c34a35331c" - integrity sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA== + version "14.0.27" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1" + integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g== "@types/node@^12.11.1": version "12.12.53" @@ -5680,9 +5680,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.488: - version "1.3.510" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.510.tgz#dee781ff8b595c0deb60172b75d50b6889757eda" - integrity sha512-sLtGB0znXdmo6lM8hy5wTVo+fLqvIuO8hEpgc0DvPmFZqvBu/WB7AarEwhxVKjf3rVbws/rC8Xf+AlsOb36lJQ== + version "1.3.512" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.512.tgz#620e6731c693ddaaf3750f23dde7f7c4347b7327" + integrity sha512-y02hdFg7c4jTfREcXf4fRhHLt7BzofMgd7JAKY+u9i62E0D1eIpLQPFo5/eboZL0bIVY9YHZA53+vCGNFREOXA== elliptic@^6.0.0, elliptic@^6.5.2: version "6.5.3" @@ -9202,9 +9202,9 @@ minipass-flush@^1.0.5: minipass "^3.0.0" minipass-pipeline@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz#55f7839307d74859d6e8ada9c3ebe72cec216a34" - integrity sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" @@ -9274,7 +9274,7 @@ mkdirp@*, mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1, mkdirp@~0.5.x: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1, mkdirp@~0.5.x: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -10436,13 +10436,13 @@ pnp-webpack-plugin@1.6.4: ts-pnp "^1.1.6" portfinder@^1.0.26: - version "1.0.27" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.27.tgz#a41333c116b5e5f3d380f9745ac2f35084c4c758" - integrity sha512-bJ3U3MThKnyJ9Dx1Idtm5pQmxXqw08+XOHhi/Lie8OF1OlhVaBFhsntAIhkZYjfDcCzszSr0w1yCbccThhzgxQ== + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== dependencies: async "^2.6.2" debug "^3.1.1" - mkdirp "^0.5.1" + mkdirp "^0.5.5" posix-character-classes@^0.1.0: version "0.1.1" From 5ba15323c212665f15dc1c031ad9bf9986cf1a72 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 09:12:24 +0300 Subject: [PATCH 09/20] chore: change tenancy name placeholder --- .../core/src/lib/tests/multi-tenancy-utils.spec.ts | 14 +++++++------- .../core/src/lib/utils/multi-tenancy-utils.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts index 0784583704..bfff03f7e6 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts @@ -12,12 +12,12 @@ const environment = { production: false, hmr: false, application: { - baseUrl: 'https://{TENANCY_NAME}.volosoft.com', + baseUrl: 'https://{0}.volosoft.com', name: 'MyProjectName', logoUrl: '', }, oAuthConfig: { - issuer: 'https://{TENANCY_NAME}.api.volosoft.com', + issuer: 'https://{0}.api.volosoft.com', clientId: 'MyProjectName_App', dummyClientSecret: '1q2w3e*', scope: 'MyProjectName', @@ -26,10 +26,10 @@ const environment = { }, apis: { default: { - url: 'https://{TENANCY_NAME}.api.volosoft.com', + url: 'https://{0}.api.volosoft.com', }, abp: { - url: 'https://api.volosoft.com/{TENANCY_NAME}', + url: 'https://api.volosoft.com/{0}', }, }, }; @@ -62,13 +62,13 @@ describe('MultiTenancyUtils', () => { describe('#getCurrentTenancyNameOrNull', () => { test('should get tenancy name from href', async () => { setHref('https://abp.volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{TENANCY_NAME}.volosoft.com')).toBe('abp'); + expect(getCurrentTenancyNameOrNull('https://{0}.volosoft.com')).toBe('abp'); setHref('https://volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{TENANCY_NAME}.com')).toBe('volosoft'); + expect(getCurrentTenancyNameOrNull('https://{0}.com')).toBe('volosoft'); setHref('https://volosoft.com/abp/'); - expect(getCurrentTenancyNameOrNull('https://volosoft.com/{TENANCY_NAME}')).toBe('abp'); + expect(getCurrentTenancyNameOrNull('https://volosoft.com/{0}')).toBe('abp'); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 2d96c833c6..58801fbcb3 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -7,7 +7,7 @@ import { MultiTenancyService } from '../services/multi-tenancy.service'; import { ConfigState } from '../states/config.state'; import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; -const tenancyPlaceholder = '{TENANCY_NAME}'; +const tenancyPlaceholder = '{0}'; export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; From 45f8cc6233f79ac5668b03bc5cd5f071ebb13c8e Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 16:12:42 +0300 Subject: [PATCH 10/20] docs: add UI/Angular/Multi-Tenancy.md --- docs/en/Multi-Tenancy.md | 2 +- docs/en/UI/Angular/Multi-Tenancy.md | 139 ++++++++++++++++++ docs/en/UI/Angular/Permission-Management.md | 2 +- .../Angular/images/tenant-switching-box.png | Bin 0 -> 50215 bytes docs/en/UI/Angular/images/tenants-page.png | Bin 0 -> 71781 bytes docs/en/docs-nav.json | 6 +- 6 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 docs/en/UI/Angular/Multi-Tenancy.md create mode 100644 docs/en/UI/Angular/images/tenant-switching-box.png create mode 100644 docs/en/UI/Angular/images/tenants-page.png diff --git a/docs/en/Multi-Tenancy.md b/docs/en/Multi-Tenancy.md index 77ca49961b..901a5c5cff 100644 --- a/docs/en/Multi-Tenancy.md +++ b/docs/en/Multi-Tenancy.md @@ -355,7 +355,7 @@ namespace MyCompany.MyProject } ```` -{0} is the the placeholder to determine current tenant's unique name. +{0} is the placeholder to determine current tenant's unique name. Instead of ``options.TenantResolvers.Insert(1, new DomainTenantResolveContributor("{0}.mydomain.com"));`` you can use this shortcut: diff --git a/docs/en/UI/Angular/Multi-Tenancy.md b/docs/en/UI/Angular/Multi-Tenancy.md new file mode 100644 index 0000000000..c71d26adc4 --- /dev/null +++ b/docs/en/UI/Angular/Multi-Tenancy.md @@ -0,0 +1,139 @@ +# Multi Tenancy in Angular UI + +ABP Angular UI supports the multi-tenancy. The following features related to multi-tenancy are available in the startup templates. + + +

+ +

+

Tenants page

+ +On the page above, you can; + +- See the all tenants. +- Create a new tenant. +- Edit an existing tenant. +- Delete a tenant. + + +

+ +

+

Tenant Switching Component

+ +You can switch between existing tenants by using the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page). Angular UI sends the selected tenant id sends to the backend as `__tenant` header on each request. + + +## Domain Tenant Resolver + +Angular UI can get the tenant name from the app running URL. You can determine the current tenant by subdomain (like mytenant1.mydomain.com) or by the whole domain (like mytenant.com). To do this, you need to set the `application.baseUrl` property in the environment: + +Subdomain resolver: + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.mydomain.com/' + }, + //... +} +``` + +**{0}** is the placeholder to determine current tenant's unique name. + +After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get the tenant name as **mytenant1**. Then, the app will call the `/api/abp/multi-tenancy/tenants/by-name/mytenant1` endpoint to check if the tenant exists. If the tenant (mytenant1) exists, the app will keep this tenant data and send its `id` as `__tenant` header to the backend on each request. If the tenant does not exist, the app will not send `__tenant` header to the backend. + +> **Important Note:** If you define the `baseUrl` with the placeholder (**{0}**), the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page) will be hidden. + + +Domain resolver: + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.com/' + }, + //... +} +``` + +After the configuration above, if your app runs on the `mytenant.com`, the app will get the tenant name as **mytenant**. + +### Tenant Specific Remote Endpoints + +The **{0}** placeholder can be put to the API URLs in the environment to determine tenant specific endpoints. + +```js +// environment.prod.ts + +export const environment = { + //... + application: { + baseUrl: 'https://{0}.mydomain.com/', + //... + }, + oAuthConfig: { + issuer: 'https://{0}.ids.mydomain.com', + //... + }, + apis: { + default: { + url: 'https://{0}.api.mydomain.com', + }, + AbpIdentity: { + url: 'https://{0}.identity.mydomain.com', + }, + }, +} +``` + +> **Important Note:** The `application.baseUrl` and the `{0}` placeholder in the value of the `baseUrl` property are required to be able to get tenant from running URL. Other placeholders in API URLs are optional. + +After the configuration above, if your app runs on the `mytenant1.mydomain.com`, the app will get tenant name as **mytenant1** and replace the environment object in `ConfigState` on app initialization as follows: + + +```js +// environment object in ConfigState + +{ + //... + application: { + baseUrl: 'https://mytenant1.mydomain.com/', + //... + }, + oAuthConfig: { + issuer: 'https://mytenant1.ids.mydomain.com', + //... + }, + apis: { + default: { + url: 'https://mytenant1.api.mydomain.com', + }, + AbpIdentity: { + url: 'https://mytenant1.identity.mydomain.com', + }, + }, +} +``` + +After this replacement, the app will use the following URLs: + +- `https://mytenant1.ids.mydomain.com` as IdentityServer URL. +- `https://mytenant1.api.mydomain.com` as default URL. +- `https://mytenant1.identity.mydomain.com` as `AbpIdentity` remote endpoint URL. + +The app sends the `__tenant` header that contains the current tenant id on each request. + +## See Also + +* [Multi Tenancy in ABP](../../Multi-Tenancy.md) + +## What's Next? + +- [Confirmation Popup](./Confirmation-Service.md) diff --git a/docs/en/UI/Angular/Permission-Management.md b/docs/en/UI/Angular/Permission-Management.md index 61169c85b8..8cc7325afd 100644 --- a/docs/en/UI/Angular/Permission-Management.md +++ b/docs/en/UI/Angular/Permission-Management.md @@ -78,4 +78,4 @@ Granted Policies are stored in the `auth` property of `ConfigState`. ## What's Next? -- [Confirmation Popup](./Confirmation-Service.md) \ No newline at end of file +* [Multi Tenancy](./Multi-Tenancy.md) \ No newline at end of file diff --git a/docs/en/UI/Angular/images/tenant-switching-box.png b/docs/en/UI/Angular/images/tenant-switching-box.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4d299c5553f9553c515aad2952c22b550fb58a GIT binary patch literal 50215 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 literal 0 HcmV?d00001 diff --git a/docs/en/UI/Angular/images/tenants-page.png b/docs/en/UI/Angular/images/tenants-page.png new file mode 100644 index 0000000000000000000000000000000000000000..8882d58d2f4be5f4a9d8e7c726a07afc6f074054 GIT binary patch literal 71781 zcmZ^~19)c7vM>C`wrx&q+n(6w#I|kQns{Q{b|&V;w)JKH``ok7J$HZWefn9|UG=N3 z#%fge8?GQH4hM}54FCY(Bqc-?0RYf15*QN_{Offqks}WPz-n6v3oA$p3ll0h*qT~c znE(J1;mK+c>Pn;NIa-R6=0KoDL7O7SpmE4Tk%WXQh{fG|LL^D9AIv)w*1}F4vzO5AG(`xk3C?x#g)RMH_)e5>ZF~ z^aZ9HDJiBGiTgoH_`$>WK;rAsnG6q!0ZD-D@*khG`cV##Pf6+VPkpM*p+W9@0peJ~ zm_Z$U@CU?!dLo|{HGlvEh?LD4+Jq{GNCO^BX@mpw$sE$bsnqr%(6+}*l3}|7>yUu- zq219sz>Jl@gDDX|%*(77XlJPM#n-Ky@0*+Yz5gP&U94 z)=r8w%Q&Vh{H9BzaE}K_qE-|kEx-GY(v=1B3h`<0*9PfE6pxrGfJ;6a9iuqT%rt1A z9k%mBup|to1?tBdn2@`9$EsN}4L_YJz-)}es?i!xevv?}Y^z{I(zxP%3lXXnfsU-(W<)a8!Dg#mNlnm! zC;|iz2_%!}mj!eq$cEVL!s^tkSDwz$1Hu#s7Sy9bi&Z0WksIG*#zP70D@Y1@BiO$E zp+Q6$bTb{O_BH>-V9M z1jkL^hxFAr1DUsm554BifN)8=mj=-F zUu%?>8P8x{5G?^RXON3w*~9Qu*W1`03*8~$1%vm8i6HM`zG1^k!^$p-7mBBI$2XF^ z5YRzN&`CH^iS*gjC}!c%X;x2Yh)k`>A6Eu4>=^7AfTS(d-_Ko@L4_NFEgw(*q?!%d7w%D#rkOKFl>I4`rON44*}qIh`1mWy_|MP z+F;E)FUNpsL3TG74Nq9T=8ln;;6zFrT9N0RtrcJ(8t6`W z3>$!}#9RyRj~MT8J)G;9w%{m*tqfQUhz>XpYz!0*u>BD>LO;OE#&DRDxb7u>s2J1%7Ri5+o)#O!(hHA^lBL*jJ zXG5nOC-md98P396<8WiA^Go_h_!NH-y}N)+^ep;W##z=3=vVi$2F41@gw}*YhSK0FvhU5s zxrPYC1;Pf06o<6KRb%_G7-9!w?_<(3|6pjdjKbl@j%CcT>eze=vR_i@%=Zy~7M2dZ z!1EXfWwmDsXHGY*TiNT7j4eyIXenE8iaxfVr(*`GC#<)sPc{vmF)}U$e+v>NqwGHp8 zN1JoiJuOZI+_;!={pvx|B)1m#n(^9m6I_%0IqZ3hi>OPZi|g6(ga1R~S;cuZ2O^$2 zJSY4qE*)1vOim2(u+%V&Txnuz;<81y(i%e_L#{!B!SDWG-1Av0Q^8Y>Q;(rIu(8;> zJRJs4kw}XqisCdl_CE$NFyvFUQ)%g%b)0p?ThZIuTDu$^op#$*+H~wo+Cy8X9c-O^ zk9YQn?$j^s`xAFKR~@^|>JQE6ZRyk1veinO8(rI6lOLT^@V})rhB>c>Zljzrk00hu zL+H_O0dIA7`Mz?#?mwMhd2-F!6xr>i#3Q`ZzPo>9zO8|z0UZP3fUJVh0=xVF_D2Y) z3;-3>3e2g&TV6TKKEvpx>#f^<@4e*c%EHPjBvO}fldzDmEVVH=JX)RcG)OVfFlaQ` z*vZ+M?~4^fBqkO^Aj%poCLW93X?T}y zo@p-WBn%t2GgKMYierhvP4)1|IKWtIL_N$C;~1TZ?@FD6#Lws>{3GPLYSHAM9%X-HY|hvLcNLXLg@u4?qD#I4LX$#%9) zo42HEGjdG%k!(Bjf<=+d0q^6WyS+QS<6Jk!jvu=6;OvFeg_+Yk)d&0-pirvNT)`iG z`+XGYAL--Fxu(x%RU;>;U=d@YI)*WBRZk`^A`c;FuAGdVYYs0CiH@#^@waog@DfgB zoCzsj^>0+q)`}Ds;SJsimqjXxZ6@(`RSqJ2x|`~G5D1rtXb%y&sE;rp(BELTkoO~sNPCektdNgM(>|}ZrN#iFv2hz=$!OgOm|Wh z1&>#lQtNK&8>^Fe5mZpjE@^l{KuQn1BJw~Px-nW!aNV>b7^i|#sFT}ACwtIfPk;D(835B^||S@+LR4{O`K%>(aBZ|Cln zH`T`6+U^GYvRuur4ZV5e#5+Cbid=>Jw9L5Zs5_I z(7)=^dRX6itl`A6Px99CK5ia#o_njkY#zNoAXFlh@R9p^&2c}Y94if)g-*-r5qGa2 zkDs0<-WYd$6av7pCMQ6*f3vyCNdWoTBjpebm0ftf2bErwy+giHRJLI}Bw_%Z?G*5r zIK_dMK~~V2;2dNS0Z@VfXIBDa)=}n-4dpHtOCUmxyZg>D2tVLwB{w}iTPwY-L+Z3M zGypum$_8t)NRVq_^e-u=Q7;%6FY$8EBX(9Feqa-D{O#9ky^xzQ3}1Fm^RMkjiix_U zsjMu3`iq7HfB_)`K)xuTuO9#i8vynX4FE_1;rutP2t@f`GQa>psKq~fmoI66=2!Up z#C?Uo@qfKR5<&nFUoqsb5R?b}f22VHc_9CX2FCp20R)wVB_+S!N=6PQCN_@dwoZ}H z-~Te8>?AZC0RVKezX3>6k@V_oujFi@tnQ>PE5l`EYfWchY-?yj=Vop9R~*3O#`Q&7 zn>ZN|x>;MtY;6et>NPO5b#~$wd$P8O#BKd`@?f5HAK*T1sk`Kyde#nHq;*w)(G#Kwv5-!;zjPfq_A^WS#< z3#ee>W@4o-V)2D^{3;V46B8%Xf5HAY>pwy@{tabhVqo~6(Eq{uAJD&r;F5Q+__EaC zZ!PjM^3eZ3Y5!YZ(Ztc#%K5Ljij9R6-k3Fd2mvY{I5C%q~4;tl%!~iVT1BnUr-;wP~a)m#Yzp_=P{%7jHMHGO40%{<7{}Z!^ zQ=kVGaM&Z;M2-D#h5v>!fcf!){NK6#7jp{eODhM2O`Xc@e^Ts61vta{--iAJwSz}w z0PEqjORS3ckBVi0^r!#dGJZk*9sRzvPWfkAsj&R78u*t@&;U>H|4=&6uY|4-%pg(?A-ng4Um;u7jZ`#EltYoSH|C!5lMdvg9`wE-UjzO-h6u&n29I(lSxYuw#1+B zZ1tQekN;T0`D@=4DbNELtkt9T+Q`G~dG2V(C#6OG7B?^-1iY~{+lyaav2_%!HfTuM`t3t(Dc-}Iov+F*w0d+B%lu~> z&3bhY7pV?{CS;{n>AOw6WMv#zjmghgNi>o>9EX+W6r}`MCPB5XQN5H zSXisRd)1yF-qh-)0vt|Hb{|T^XSY6Am&Pv`uGWCoTku>$j=|~CJ?DTT81D?LXGAm; zENC6|$gd{v;S?5Fvu=|Akfm~+ZBpdp!1H(K5Ph|^i0wR$*~B?t2Gcpr{o4BA+O*%fM}aIx zReIOaIj1gE;)b^+&0=NG>Hlu^*2-QX;QNs!5)^V|o3nHUG%k>iy;M!xXt|VBJgzzt z@q4tdw{CpcyS*c=8b;)>TvvgI>@?Deg(x*Z&pU4B`p@2A6YbyetLGZ32Csk>CHR-l zF;)U1LB;DSo7JMmdAWTpG7=Kq*9vs>fOc)6ZlY1=qpWVrU|yw3#^STTZPJGvQ3}vh z1*YRU0XBFCSaX_s2~~kjemK`G+=@z6Onc8|vksBT=ERA(WH`T#q3F5sct}0#AN!tu z^X=Yv{aryu=~)rU8}YTGuWq-o;b^Va65-{R2^m@Yqh*P>96rrOFuWHBGo-`qy*hZl zcxH!L5Qa;wTE~-V4-$NS2ko1=-f7IIrp8&;-w|b724y>le9f9A;U)LE_T3amRUvoy zHW<#zwoF9-6$4l!ATfcPVRS?_&3flL!18d#MJ2`Yv9|jl*v%9FCwVrv za~$01;wZb`2kAZbLXvmdB+*e%PXgC+1+J2$?#rbklbwL?Xm8-{&^LOCa}T&XB5H}q zK8Qrq%Z0h_=aWx69sc8$U7k1RrAr@gk8!YfPidKbhUe|~9YxlB`8MEm1q34wvC@RXd= zgHGzYpAfk`Paw3>1Yn=Qc?xzJTqP#u>O|^4)S~A@LzuPa)hZKJ5ifGxUnEXbjG9|#^gjT|w%okfW zjJoRPVCRnThLUL0wQzf(md$S7AC_;ijC>HnAH!)uzE}K*-RA^{%1s(w{g`>60cxLJ zoke2zC#$Yi+O>*5C(_DN^wS%11U?5p8uNM_l4-S6!5lP^+?dhb8FgCIF=*+3kdsR! zirtf0FVWp?KsZ3SftK*tSqN&I>j>m`YaPNPNATI~9#koU8-e`1ywU$P5&BO4IxT0d zB^^CbUgv(=RQQJhpKd-X4WoZ*<9L;z4&fHz!=in+1AWE(ihr6%$+fr;fhKb>RSMjYfwm# z1ma7JKIC!M9SohCT(GmRCEaJ!h;L>?j1A0v*ckm8b2{G|{{x;@Q?W$sFFev(O_h}v zi*fr`sHSuz1+Hex4cv%hkRyt@*>1NR6@#@J<_-84=Bq6ic?2y3=u=|>QCCYD3CExs z5EOV^$E%FDrRO#h**?a7Uh}QC;Ds^`9X6Yla&H{0C%x0|^Bew6_Fa5>)RgnY<Ri$(l8}uWa1z$+Qpgb>-NeHH$#dA zgvI82cjB{1(q@-KdF6YGpLvpjH9Q}GV80<cgr&7ItJc8a$_ey_E1k6tU(&cykf;i>6r`B`s`p*Yi}*Skd%v9 zhIV3EZhkJRfTmq@Dym-Q%vWkVcI^jpOyas}rrdtHm??Xxcgc*2yTkM|^k9ek#xe8+ z3EsJVGyHiG(+ekj%VL!lJ&Aa1vK=LdOYvpAoBEtRmB#ADM)|gU z@c8mIit*&?J#`)dPgpwHLik&0sj2o)wL*`Ag=#(d#b0ZLRNQk7xrKiOlJ`q-J{kGt zEuu1r;SNSWim+eqQ)snD+8R%d-xf5Gkbp;$U{&vKXPSuN%yUNhWbFe>(e z(6}UI=65^yn0r3jL0?*I@YaqM$O&9*)BXbWNYZRUxGFYoM6@*Ygpi#@CZSI*gs-GIOwjD`gKRmy(O?J?RUlECdWqB!6IufNByEM2k&hp42HmT zTRT4{x-Ym?1zR;B&TZf1bB4~96aX~|Y2E@vD@cl&19HwigQ??LqT@w!hCD%gG_Vs4 z+mP}}zjV0v(bqPP7!xrB>NW`{S6voy26nxk7Of@YX)7=!1)O9pQjR7w%#2N?LLbf@ z=eLIt_&-R!4WJl~{zUGTQG8IXDH`QlrA0Gm(T)u1H7rU9jP?2B(+;4rUia_=BB6S`7ja73^EM~34uFc>Ltb;nKf z<*L$9G=8j+=d~J?FBNgGO0m-EOSwe8V!-{g`y9iT^Ujmp{JBfE=Mh2}$TvKOSHtDh zzjI|CA@Etp^7Z9F6i{*v#@#82^T|R=QW7c_zkMAwk*CWg^<*C6h@YRtPF5l41I1Y- zC*%zRZWO36r(`tmD;{ZV6XXUWmx(TBKzibhLfeHn&JYWSQkR7mHSSS9v$zME@K{+g zAh?x=QlU&?yN42u{EWs@SshG;x-zgkqf?@gXKczy+3A)iA&z#-QbTne{lHz?W;5wA_!Y2y_S6>@Xap6o$EGCZ^GIfWRcyFio;AgJC%~BhVhpcF z7*6T77fv+_32MKA364@>i>Pk}|c|1WJ;C~%IvC~m&S5a}U*k$13(bju^?EtTaiF+Q1 zV9vh>L!a3Ko9t6ZZOo!ybF3veHB`U->`Rf7Yr@c)e~_@it?+B20!~b}s-S9~DUba5 z4ly&7B&dmmCanCl70Q;*yU-iBg7`vJ13t2BkJ51YhwT;NXE)e6?&FHhps2XH`*L^f z`@z=N+&qKMzU0FOeolioUq??xS@V{Jbp#S)V!%J~5D%80ml+;D@7565;5M@hM&^)Z zq{|(-uXBX4OkY2JPzyQYw3jc$c_Jdnh31X1wo)azW^k<_3crK-wF%)>a=n zu7C7Xrc@K7Ky0D05thQ{ND|6bkTVhe$?wxAVt2q4){ohLmbjrVCr~`z#NyB&YOXQc<;2_FP@3! z>QrdUaM6fz`#KWX?|!ab4$IO|b<1eeAn-aQYWu8^rG@uKjqeE884gmr@835Y4-yr! zd_asDeR?T2*{uBvRH0^fF(MDO=li%*X+0?aR(#nLnT$jL4!)H-p_4=E-QJX%$?qm? zX3Zg;&}I}Gh51~_bNlj&3_l)l+wK%++x>)ya7@~mb2NYI1uOC}+5raR)Y^+8&r7QY z-z5Vv$DOD0_BLLRqEqC!Ud^=Ylrvlq` ztqS~>r?b-F_h9hXK{F!mSHG`C=(qGMo|3oCHJ+o=M6cd7Ix6!i(n-)$lG&LWID^%i z6z*h6{PmO*a~0B;s;vwDysO)ca9EOnhPE|Vh18}*qF zDp|$3jGn(TIyT)e8@U*J-Y&a74Pe96Ecusfb#OY(ye-|NNyK6^OI2Ml?vIIfu80Kl zxv?JIi7t!+xmX#s<`J!8Bv>h*Y&&=HY1xNq1Wf`P5DJmQOqu>^3pa3 z5G6T~x64NURIo`65LGI_yVQa3CM1_-&m+*R(?+XP2B-xnwn&#e)cBO=jXjVybbj@l zsua{&WV#oFB^HHO4KNckD8N)R z(|y8opm^3xQ`tz&Vu}ob3Q$6gMODc#H9ooQE>ja4b14To#U1xvs2>(C%Oz?ESkI|i zq!({pEo{P5mn$II&MN0&oUdmaq+7y)m|g&s6Sm*}L>KvdBM!#(1A{{+XNr>h+&ZaX|3^!PEWw=*j2BBTR9j4LSf+%BLv4DP3n?orJf4@{$^XTdW) zPXf{RgYj~Y-%j&J-*fDoK*l>;te57qSS<_q!p8F4`H8?`Q#$`xO8G$vVaES(wo-_| znm(1othRd#(TxBy5dwEIF8sJv!N2|K&7yoVsFGmI=Og}Xw>{}Ex54FnN8hH%l0@Vi zFhAJz5;)F(Gz+{M`n8rjIg7t@T>KNtpRXo2Wb;E0_?y~&JV%4{F1;`qL0>jLR%iJNko-;t!YChjH zgkZ2YrUL|v!s6Vho`_q}&%rhb2#9_xeJwnO+RMB~(8>F6dHnX|duPoYDEKjg2x~qM z8WlutuE8dlOYPHIEh51aFV2=iSo5+FjHvoXv$k`@0q4A6Ps?fMlmP5PgtB6bdFtvP zUL6b7YVuXf9Cng25^?26@_g@qEQ^%HRvWEJEE5(-_EsYAxik&!w#7vm$K?h+d!~&{ zZYseX_V-i$@KDc~502^uPX!KS$ym|Aan zRVg_*rZ8uk*}>EEx$Gh%;re*X3#WlEzsoe3NeYSz#SDxJ@%YN-iIHb?&(Eqk=nsD|gG1l4^S|Oxi(9iMR_Rs$`Z?v1`_SJ`xLj{-vW14O`dutKw{mgSn-K~-(uW5mB6-X_ zvXjhIVYzT?he>G2cD*!y%$G*oP>6U;OB8L7hCi9c_`Ab8=(E9`)15(JPko2i-AAg! zAQ{N)(2@||%ZW(;_tCEnw@SFc zcmOk6$GRMsGtaLsK1&d;LogWhvh9y;685pa6(th_8;_;i*Z#L(!O%mu3{OUOAVmZ| z*j2B%%M4b_bvhpR-4ZAHg&V6|7!6Hk1p&fm~Swx#K3 zdm#vZfM=XADtJD`4u6t$LTJ;_!(&m$^1kFjfAYs*)5>yXQ821#jdEYY%@SZOZMt$* zBTRg{6x45)^gY+LO50a9YdhX2dys6po#KT@SW)63+Fo?HKV7TDdtS7tsM2N7B5b%v zLVs#tN^H1KzrW0AJD;>Po+irOD0Xh&d4MR zy*F>c&G+_@AZ$YPZrsB4q$7j#ox!H+IK)GLHc*F|&xj?%=6b!fe&j*i6#|0|y{FCU zZzJp^%JV5zE%E2NNfCUcU|#)FZ(7)`t~Vn1%+IjR_7r zkkCiQo^j>;WnmvWH_tEI5`8hU9$m0RVOiqSB`oTi`TlgKK zzq(HxT1~IW9MqI`g;=o{-m=&%5MYzkDu4)~I>-@aU9Ku)~{qIGD@=Mv z3k3$9Tw`XusGyGMG^#_+3_ zbzj3>T%)CQ+mO*Zi~7`W5P5hPzUQ}Z?pN2JW3V#FdDPg4RYbYwE1X8RL+u1YJN2u( zerA!6XVU6daPKx8W8c3+^mogoQzP)b7f_ScU2C&iuByMT%o+`y&}xMHTuwgne^=5h zUo5*@fuH|)u#+0;-2tA6>3r;^V7gl~C}*(^0x~##VKt_&#*?M`)7__fzK z+Cnb(bO7BY7&cw(n`b1*v<&CCibNvbyRyBw&X+j7ZYqNc`?*6wnNa7nLgKFe_pD}} zOyGMtZc@C})_C$a`Xz0jT1{3x`{Q7T4YX7#tqB&}jpVX(=Hvp)rK;pdzBlErcb^vO z3d^N(DsER}DQ0!sV55LIYpQ9bi`mArBjL2BM5-i~RYmLDe2EbrI|+&xO555E-!B(v z!(~w%c6hOl@>|_`fuYv`Lg8MtD_`7iNlAs}VM(Fi)NNT)8m{f_BR=8p(A9V$4>q)w zrOR}6oxAL7*97A4l~a%w;XO~mP#JW_BroBS0Oq*LhZvO<;?SJZe zY7NEU#Zrjs)I2^nEfgJY1;kBon)HqS~Au=~mb+Jq;T6cEm)2blG-2E=E6IuHo1d z8$+AU+O`}(|K3*8-^lLLs^0I3-5IwHJ%we40K(Am2(Hv%QhT|-DEoN~gHDqK#!N1m zcw*1R-2>tC6h^SuZqWZ*`t!>l77R?)|JW~n#NNxOQ2M@v@)<`adAffv{vvfhaPotE zt9n{R5&qy*7JGPnl6`{^W_IVcQOSGylI|OZ+fTerkPa=6>?IXesYrDClr@`94eX{$ z|C@F6&| zlu){ufmf|cvWQFUx;`s}l2V$1H{@e$^n8WaI@wQ%j8{9Ix0?`7suUC((w?N?zupAx z&k+M(k;o{jlW}VH^1M^=#{$RkF*m(GLDJd13ydqZh<9sb{CYVx&-|8U zoO&}ca-I&iOrTR(u83?ydlSwyOR!ls9shNGz!%sGV;Q{Gao>s$>}fXbecyF!vs2me z;sr3YzwLLf%|4+#f9CUq!2hR;A}jq@r4a3s)L}*&3CUD~0^!d;e(;;rR|sowrXCX| zhE|lOIz|n?J2ZfPtIEKV?eY|WdO{CdqC352ow6b!Zxdmi+d^QnNzi#pECP_1$GYaX&2{Ie(BS{70d(u(plrkC3xp-jDi<5DZDUUdu76V=5J0VgzYc6=(U6a4jamXJ` z=}}e-Eg#-+aLt==9&Pz|;T|pdOT~bcuJwsVnw$if{AlZjjqv}PmQm%rl=jBDHb{}A zpccDXvRHyshF^Trf|zQu8c+@NH8@?U0`Hz8L^Z)1Ox~*7W zIG?NpwN#s3&?svPoqQ*P^cprYLW;Gqn8C0>r2py85F>&>m>g7?Q8j!rfk3$^)5 zLnnfaZc?|f1B!d8%-eZ-vr)n#)yR*7PO;MlJkRxOmSSpeM=;b0xP(l)CtT>METSJu z&gQ#9WyJYu&v2IcFxYCkjoM|pg-+RRQrPp8id(&6W2}oM`(LW3%gxgK305d)YFjmya?0BRr`sD0Y9}SZ!Ho3>6!Dy>q<-+i_xU4T$lBo%JV? z@NfG@tFC9g=LSMuz|wT9cX(t!ES)Va^Lu!o)M}TyLH6_NhC6&-?V97MDM0mj-h*+( zW95R}a4YSgrUH)U3r)TSh8}c(x{Kj^ANgcockkV7x{+;{^evryU%T$BupPfwgP&_* z>F&vDn#g7oG+W?Ql1oIJI&(Y-^(W7V)y@=W#()nx65ZlI>#2Ol(DSB^eLq#9>@0=9m579i3yfrLPgcMgZgDD`oB*1gkG3L{VAR#uOXjJ|_2^I}6Y zR}5hl;>-W)dvkC~-`{FL|9o5JdZdYlPaz!A%#TSv&1cWvf#J!_K!ZTQ;zKaPmuH`a z9%EV!>y^q9co1#N)m^$$Q%p+ROE^^0bB&5}mv%;lbkTh%*Lr!u-N5JN$2nt~$4Lv) z7*aW#?#aT6^ZIwLL=f}CSZMdBmdwkX(MK4Qk+x{#j8#?t$8TQi% zJms87uL86k6m5AWre1HS`4uKuUppt8drZc^9ykSM#-Db6(S;xoicV*@$qYKi2Vk#( z4}Czxk2mK&1=&~{{G#un%`J%{dEm^Lw0f5)Fb;_}LL@Sk#;HXvmrcd^edok2MTmN9 z@azS&skhjUcB@W-J3m6iKoYpRxUSfhp2ixIx&-8xhw~3XJDqAT4#Eg5eH@d!{dN;@G74UBn`p}e-ew$-WWEe;a}Xd)Yo{+Re2CkF zEgf`pOv>bj3PUU!hoEUqF6Rys*?O`$OgfW#?oh7_3=64`X=`oTKz*)4#dh9wEynqW z?igDXg%R={ ze~tUa+@O7uJ>(j9e*OW^8-nddp#1^IT7itC_0@!WRp*XO+fbp?!&#+Bu?dUo4}~>z zI`~>;#1VbA3e%ck^)!bM_rataL|Nc!ZJLv@`w>P+HBnSPiW=p2UrYTD2>9(}AG-(F z6*7zyMNm1K8ZWEnvIUdeUs6VT-9621-*puoy$6hPdjv?WDvo*LpnYQ))zvgzg7e=G zcxSqXYlT%hT{2ByH;X{3zabp@zM1CsoO*A_Y`S(y-E0nuh>k#00tqpUN}W19cq=b( zONV=^r6~@a-&FQ*y;( zXIVeB$^9K>M}gNT=I%<1B+;WjYZ*#*Xj+qCC~pcKs4fafqDdWE^+Rp&pN z{HU(WJKwP^!hD(;G!p11p!XGcBVtPOAN0rQNP3=8j_J`9NsYgx!P8**u_DOlc1fFU zQWD%3__zUAwTK!8TY<+7xPNW)(mZRHF5 z?%LmxRo|n%G!5_0oiu3KbRJ|hf8asOdaoSCB;Vx5H6LY-;kK?6;cy{!wLavGgZtvz2r8t^l-X_E*3B1TGNTb z%IvHeXt{3tmP|X0KzAB=b(z@V)4ouRHocQhKJYqZ7LRU6GvAbyUFY!5<}J>GhOv3- z+xW-h^0|X4$M%Ny)9xo##YncGk;g87ME~q zSnps993b3sD-r3GHFV305OTEhddt}56gy7jRQ@tnT+n%yQ?~IK>*JHGm~)d~#3^Ab zQ5L&L#VD{l$@QC`-mfGU08s~4^$u2X&k40nvi`E1O#MAFn&H{^n^|k(#A$+Mv+smv z{4ehah4~WjDN;xV=DwXitiEq3=SrI^IVsdS+>L6Sj*DlUc1~RqY&L5|t^$iiTaC)< zJ+;w?X#sUuTc|ZY;#^)mEHiwG@6BV8LH-f7pCt0bNhULFxx672#2n0R7!c4FdV*+V zmk=Kg2yId=5;j|xnbJ$UHMm*hKnMNtMyM%T3=CV$cs%#Rl7|7BwTqCyNN}K(z=01d zKPK6Ast=PrVbcZ@-+t zTKGO!KJEay)12qW#DHOqw(Ko=2(b*o3kaBG;`>bdA){>gG4lfoWKtY9Ta|hRu`0!4 z=+t;`%>l*bu$Z0Q z1%s;UDrEmW6`DJ`Mev!cX;}Mi4oa>hz1_hej!5As!mro#o)f=aeRg13n=?;mm`xdhON8nD)_m1vwiM6 zWaZ|r4jc2mnC-ORvtNz&<_F#V(M)NR?ljAK?m;Xb)8Tf4G@w*wM+@?ZR4rYgx6knm z=b1cg=pMPl{~LqcjbQRT0Rs3d8$e6jI=4eZh1vKJRtt zEA3Tl>}}^_csCq7JeNH*djHp*_WEo%;?v5M*`0LpOC32@y>_?_B_! z{%XTb;8M-TI+%1}v>lxkgkP!-4`TJB4SDkxlX`YW9bQq*I7>$tI*wI!Ypid2TF@E7 z_-^-xb3L_Ls1GA>-K>jj>UnL6*VU?C=g4DkQ%y~8GBX>OBHF_+b1c1;hn4usFNZ9F z(0!_>)7dgOn&d(!+}@?exjAkQ4v{w3kq zfz{Q82tWZuupS48{k+=+(w)wZCS&Dn5g>G3IEl6Wp}J z2YDb>G7oN-u$>IFT_3ay$WPVQM7iA@AMSOs>#2k)^9-9H!e%9JPb7JgL%?-u<~$AS z-Q&_CV`gb|-*RvBZb-9o>Z;N4Do*dk- z`QVmQS(-9LHsF$t=y}83> zGuuonH=1o$$)hc0ihH~%8rXp_s7{!#m~z?<(9fqdz2n8;1(?X}hJ^pq_q&i657@p6 z|20IT-c0&t?q0Fnj6Hh#jc1bIbT6K6ekR>^Ydhc_)eNNzmlw*msto2^qlZJkvzn!5 z4)agvAIClL>u?F$Ix&xv52@0yY4m!r5@Y}ft%kjVx}d(#Co1MV(CVa$ZE|*S=xMqu z%+9-#zEHt_F4k>!BJ{CSIQ5e_D!hz^Sw1$jOTU9}QBOkw=#$u|bx|<%VG8_Acbn56 zX%Sn5X|i<}xV>?KI8k+S+ImtxGy(8`6d*T2>Wu7CY!ia-lhQ1pctArmbvv0os(yMK z=jN0Y_(w#cQvQFey=6eu+ZH!GbazR2mxR(Sf*^uQx1fY{H$zCbbb|;e-Q6u+(lK;1 zGz>BG%sJ<|&%H-|zr7z}{(J9Ld#$x&{Wha+tu=dccP?1|#0MW+9x&9-ZyBXtto}L^ zt$Ildr;Vx&_}mJ9O`47SLfCyXlF)}_+^8qtKK9_Hv|b6WZhxwR!o1dure4rKD@Vn&)#wFvc^+!^tBfJ$z!NS#ZBpjpu$2~ zMX71Vpu5%RGwnzR6`#xfpFVBxaliNS8^!JDh~3?a3>vxbwAKw-#7@$y9({`OFHlL_ zEgs`-w8+toe|_3&e9CXR^2v@OFi7A|c@U=|W3Q6S8qENvJL0CTfmHvSNi={Qqyyk%E^aqSJRB#nO{)x-0`5$PQf zc=n=U*YI$6`C0&{%m%nea)Y=#gSg;5_71OB=&%AZD)0F-e*=w!=!R||&~uHyRRHFU zD0_{887H*rt3?C5TiyH|!ILn3lxc5M*OnCW;byaX?8B03cfMCS)HB`#XY^LyM^OZpP|ttX--o3j#5I zU3q#H8+r8|X?7udX= zO}Um+eUCP05_u(Q81!IZ9Up2U^XTo7>=>^nx)gO5V9JaG=6`Oou=)AT-c@E^nZ1)> z28g}7qMcqjkC9Cj>wC2*(7FQ(;HI4#IFK01qt?epvx!uQm#<4-SliFp4E6lJv(QfA zp1H@v#g~(>nTL8gZ7P9s@Wdh{{`0J9qXxCh=YD@#iuI5VwbO$EL#?hd1X<`r-d9mIqbV48lg>T;wV}jy$+046Kx1_TS<#^V`Nxe* z0k=+%2kMd32Fl*DYLfD3fAbL|VQ5js#v)yRH2AjqHFqoUy)L=c4Uj^JJUoW@h2Mr` zS@Y&yDjBaqE~amqY;?A;JX*Q;2iiM>QQMJ#&!RZKWP`E<9pXvlN^kOCT=pRQM9(ml z|MZRWVL|Jo;*2Dhl1T)A3y)_0)=}6MIEc(cbdnX{bh|GvNo2*hYk(9#eEXB*z!5nu z*^!;D|B-q_>_~=)(}ft7FG|C+o_|Ud-op>TP0>3)KdDn;Xa8=|?BGW$-0LcYRDD-# z%J@Mfqo>m7O$2vczeV1jaP&}012GSk^1j)a0ie(s>*T5mU8l~m7Jg4&Ze%lc^i|EJ zvsxR*k?&C-MpH?$j|D?X{Bu*CCwD?^;fW9Q)GIu?P5S3Mj*@k))_32uKeTt`>sIHg znM-vr1IuW1Qw45hxJsmqq8bpksGoR7@;I5^y@Z4hVct+kGi)LwQ|AkPI?J*vTeF&g zU|#RrpEOA@qYx2n)vgxi=|v;WfzN9{z3+mC&RCXkl5`ygetc4tD>*mk#x!GxoBia) zE}q-I$XOvUE3sJf`?*1Z3}i?pAzOxtHSyvFCqQ@?y=+}%V56A&2F+B$(vbDFB*Zgi zl;=c)_(FHJLf%J*U+6_GgwnxjCfD=>$S=n*>f;%tUv9G;Pbvp|l__FHD#(@o_|Zr1 zbiT(RKycQLL@80Ge!_(5;hX{8dv@|-Azx~7TDzW+JQrC{&tPYZw?N{P$ckjW-FA?&`ZEy)%^3G2o0rQ#Q0vgwi&xOW+!eR1la7ZX^& zdM7POa~7R}mfy*ea5~dW6MF}4(iqv?^A4qnB?qtcLveQGWhTGt@p?S8#%Sz~*Qr?f z*o&|!_v57*e&6#*!_!9hRj2YkQJ8Krb@SMrfSFw7Hr*m?H``M06LYyq-QyX!j@P+Z zxja(@B7=c9mHJLUjZ?VHI0!(!d!{FEnN2$qKFxY` z^k$DzEj#wNI)bU|l{nd+1mwQ>dTr8XvUe*6^`E8DNN_Kiovuw}tNy#tR9Xgk&ee%j z3K=N@=aKcv6Td_3`I*CSn%hV||%R(ANUNFJCTn_a&KjPY3pdYSRxBdKZ zGbXR!?_247x6gkv*YhI&{n^F*8)j6NNX7EU{*fXlxoU0Rm%12%Z~Px3Oy#yP6KV6- zwzAqRO&Gf0kv1A6mG~Kvv8~O6)l#bvXD9msLxSGZ!eJeUm}nx{0z2I5R(!W&#;eLO z94Q&{Hw1U^>%$19Ga=T%R6d0}s~x}aSy(_lX~il|zr;p5vi4KarHEjigE#I8Sx?;v z=5lABXDH#{>-h4Eq6hW3a|I4aXH($?AwbF$bqj~T+vk#?P>Yr+8L|qHacRUuAB)>j z?egP^f*2_|?2}5B%w98*zA7X&DP_LXP4W-axr#GoRq0MgZQ#is%fHUB_hK#K{Os+L ze=^o_p(zvhtR3%VdjsxCO~qe9K)RB(<0||Cf3d*1WXpWub)=^#IHyAH{5kOWy?c@8u== zQw!*9Wy^D$*PCzVS`c;X!292`Fuj6|#5E(U$0Bx06DclDYn^s1aX)P{%b>5u(W~gr zPJ{$eTcVm>B##*}KA}+8P(VBM+j*7ER4RHEdz#lai*`K8Sr(r^KFXx|y`)?nWb80H zcv*yErBk0~bgW=U=q)--qs6mC=aQyAMF~cI-%|ND`OCSg0VA`?fg&=h&37wOdVh3b zd}|!EfcShciqHEwAtOam)PmPIi!ag_PH*K>MIGqZ^A)|9x2yP2Ud2y7epI5XN--Te zOG}JKPxY8PT}p1Mc)o$9X1oei*x!sj=W28U(n5y~TS%ww z^1pr<;b_Feq(rpaW>PRa_4Xv)SEu%Fbt%9ySCtV>JoysH_QI&1`0c~#n*x*A1jN8w zjLITyoyTNg_A(lFjf$DRkv3+V1s2PL$*-2_x}p}Qft^~$Tv^Fn7%nEpxGz|Pvqbjx zd#hiMa(q@3dp^UR8JH4qAi4*-eV^%S!SI*Sb%@COJs=0^j2h=yzU|~fFPGY&0M3TI ze`o)N#re^h8Wzkd5TouAyXa;_;d3BmU3M0v(fnak)VR)Vso*EVShd|6?X|(lB&8OlxZ4ET`A1RqT0IVNY5}5JPKq}UoZ8F8z zDCJA|MNW5Q?*puBe8u~0`V;mZoD6!EB5r{R&h4O(kS2}nq1*A-aTYBZp__u3pg=TB!@XRb7 zA8Rx%ydAknJ>J9AHT>#U#9p<)MQUz~*coESog)!?c5OlT2Th>D6?Zv(Q>ncJd^puBzLCdbS!rR3PSc`a2g2gVP zM98z9^EL4UHwpF&;-VjX2F7$Fm*W1}e&1aRp9fPnwHIXJnUkYWc$2K|nnK)ram1w?-jA0iQInrm6-fZ;*t7I`g!CY#=fR zrg*>Gcl(6bI!03RJAp8dHRh7H*5AunzZehKusxnih(*FG*h-!D`YynY2`O-v5W`bgr#lw$dV)0BEwv4@!NSon&-3onDp)O>EHpo+Wq+#>2f8s>2$~$1!~$^ zg|98@r~V~TJ=MJq#_6Or;f;0Cg5H|%OCX^{>WTuHChzM)E!uxhq@RQ8@yF`~j3{@? z%*FN=l-v%Tf!W6ws#>1knox0vAL-wfinVw5?-lj$u@#v*a9Bd@vz!Tg!}?!nb@9MK z96%XN9ne6{ANk5V1J6?$Sj$(x5q-(%$two{JwVU=prJNvVT0aZ&RIoTQ2VEM%( z$gX`p*xRf5BANmFYJ9Z5OVIsQ=3KMMP>}NAD!6mvREH=$AKVH7dOe_wn4YH^3fxqYlYlSnsX1 z1qV~}{oX$UqkS;?W^3{u_6Or1e@6d6lvjnrgUAE%N|66J(5UcVC>IVrN&bIi;0r4p zJ>yF|nkM4kJI}v(65~TEe7ccqQ@xG6RSv^f9_o16`VA4s>%<4!#?~f zznoo+6vUieuz%toJMSR>i!_1gIsRW8{{6Yy1spI$?c%ya>5rX*B8kwk(b0uBQngY4 zD3?g-2|{$Pw@vC3Nga+te-b^so>~~;6>KNtRG$m!kJ5Rbqlkfw3jyUZaQl6*{S)pB z9N5GI5y6X}e*_UU>{LhfKgRc8vWeOKJLE!eNh}e#oc=rxXqX6{OJjdC1F*fhIqd&iZ(&GvHvf;w3?gJieTSL)LomjCa+|1&*6`Yia`U!Gxup zgg-w2A@=FJ1Q>Y?vc6}X37giDiC3i{qmA5Ye)aZZD^5&#WBv5&wm+T`RaCZDDK9sT zxa+NQ9*t8=j{9*6uvJjS+XC8V$J^VYnj|-NH@J3nZbDU^@3Q&2RMjxw@!+`3{)6M) z@nW)qt>{ZOUh){uYx0;*n+-7_jlz+YxA)De94`uZD%tKh_x`St^_5BY&!5Q!T0+Eg ziJ6HL=6%;ATuV=yj*?l+Wd=67C01ot$zq6uWBQyNE_Jn}skrR3_nNAjgkN^>-h8%K za6A}9f^Inx+>BW1`^VfK-4KfHi&9P92=9vdPW!mNIL+YXjDeuRHrlw(UU{KKzYyRJ zsL$`s(ZF|g@guG5=)M1W)V`M8fXnhs|2q<#w%D81L+Xh&q^UO(l=O8 z(B6f{>+!ZbQfZ7XMF^tsQj#U_@of%;TkgMWb(Q7{{DJ}cYaBQ%xJ0$ z?O;FpG+hibHL=m|$Rox3{KJ6CY`wpG(^j-sWi-TDLmk=kDXmfa*X3RwTic0Lw17Lv z?J6Uzfrpp34oo!rk-+EjEXGNFB4(lU$=uk;D)W|@>#zvbY{5`+AN+2^s8w2Op91r=G`DmGUQIK?n9@~GB) z-jvI=p948>J#HJd8+Xi|oj@Cwt|1x1YNO>1L&I6aK`W*w!Fm6ss=zhXQ$d{MEby~q z52{&ykXX#miFOqum-}j0oxOTaMmIrjrsK)6=9&Ikw|p`1qK5P<7W=KARu7EZEWx{N z;`irMcbyrh*{_#FbSavxe8_LXO=niR4T{a}vLuNBXyI1{fzc7J}_(kIM`< zw6vnSiO_j?ANqVdph)vPDpAINpLzTpApQl&)G@EnA@l&e(ir~u{!b301AUVK9!_Ym z7Wx0=j_qd%;hjn8fyX z{dH#ld$h@@{R^9FW<|F+&c)B7V?qq={Aa9P=vY7GC9Jp4_kGz~mF zZ&p_P4Yl*z;O5+a1@GGW84j~QNsKNA9-Ys$=aT+NR&~-}v3o(!ibUW~@{Cmg)vy5^ z&nBz?JofXPM}+9&)E_u>zI>vR^nT{(7@ZNl$%XSr`R$1N`}qObb*jEniF8?Bzs>fP z`hX(+>Q(et@Cx_*{5)I)JG81u|BZS74HShD($dlx>>5o8pFVw3gkx&aJ7uR4(iy}2 z5943?FN7LciseQLGmvnoOZ&eX3Wpa>4Nm?sRXPb_miCu29iz#-!^4UZ-tx>yfTw0M zN8SDpcbnt6a)jjM-%&&~YNp%s&F+2WV)BK*d*n6T2i=;ccU3FR~wyJ(ufA~rQ&=fnAwk(1CN*5s(*d`@?gz!o= zmy6_&DtS&P<$wR#9eUp02Ast7gM(>|{(oeUyPSu<&aD-9DnOv!+%WxMCx?q{XDaUOEn82Shh&xc)AqlYaV~(Y4dpsFMai zK5u8W3NJNgFe13y(5|F~bP*SlZKopU2#Zr|qW;EK#|!)c5~y<6SF=!SC2n@dM?4D= zi__;XrjKGge-MN|yj~M|g8~e}4g2=tIbS1f0pKQ2QbW`Bw|)TTQ2KjbeJxplbe_k!+>i_Xgn;qcjxJ0y{ zHFLizm~F2f^OjM}`nQ=WjD}7Xtgcg6Gq7!d;J6`_|6cMFtj~d=naxI*jSw+}ell1F zp+b;bdKC68fvZ7GfufIgVhhmQNiSXb20+EVBqk#TbBkM27@Gdg0@O;-)!wY9!SWB3 z2k%u7CR@S>NQa-AOCtctr)3H7K~`6F#z(;VZ&axjlF|jGY`K_z>-;eW*2Dl}XpAO+ z*t_0>Io6zA%|7FcxaVeQp)IGiPk2>HQvI)*1sWqx1C0A1icg=?1t0pIv=aeirMQWi z5tiZ&&|1R|yU`Ho+DSjWiymzrAOR3>D<^U=|5g5+Y~-Oan9Q5Z3VN&ZrNZ&+voOLc z0dAGsi+yG!)Qe;!G+YZ6%sfHkXWLF+8iK-{1lvrn0|EjBvjfray4JdL5zob`Aynzr zzb%JA`b;_1L$T>>j!9kporuVz-*UE*(Oh5A$ zep0^iJ85nhhQ_1$-KR>luP<-iJqejr-*d*vdeeQM#8CpN9u=~xhI`$Yq z$leXuv6-niISIPBi1g1mgo~tDZm=#+$4TvN?nuYxL}uIRrivn+njOTccQQ}BUYZoH z0fxFk`)fxeN9OMa)iVZ_b>+(dIe?e+jk-UJs@#7Nwg!F}N=mexDj0H^HDs(`bx2-v z92y~fr2Ph$TAT^)8r9ZP9qxlHM(b!Ly|sg^FqdjLK$1w;>>15=+dIg11+SZ&_e?)I z!Y)!Ye|#QT70Lrot_htRd%g@@YuqtP;LCeH*cBAP)TTrt(J%fedGE1(HXOSP`e7pe zpA*Y}xh-KNWDZ%A<)}*pp&8Qe+M1i~R&;Z6?mJwys&!){i2=nz%N$h>ysmV+3UZtC z(V^lBGW?X32h|k_e1%-N!d8e>6T%Rb_s4fwJ&V=7iwox$uM9aUpIWPRw&>P=eADXr1#^wK==yM; zu^3+2KbXj=Y|*Qx(`Mahz1U`8V#=uuFHvSLF_Hf&aozV!Z5 zV%VxXNLQ+q_=Smy=~*J$53AY10+nriFDF?p6`98}xR;MY|aZ$%lrcJGT0Q=@q% zJGbgjMBEh^>mFr~-qGMHhKs!ZMefyPpGTt4>Dr`A)#IscSEvuwphTYy+2C3LwVLdq zG&vJ-6Z)ao+t$#rXDM_6i>@xC5`8#5r(?X=8DQOdJcqY|5eJjbJE^#vzO|v+^+c3v zUy)HE`%wmN)Ei{|YFxwsU8W2+m93tWB?a_%-W@kQZaARvAvN@X0D01uybp{vX@OoZzkK=P zOzKOXfD|JI;f1*FYBf4EoUV9*hw_tg->g0K(<=Nps$b?9lf0%)<#S5%h8>MBHK70NfFbWqwzV-D?>mZ5yT1(38Y=6xff^uC8M zj^rC!m6mx3j&WiK!+FdPCdgz=Z|`eGJG?TS{-?>0A6q|X%B<}7{*<2IRYeH-8c;5|^s4L9>-9FNvAqsu0=1Iggw<=jo~;8if+t!c{v#%2+HEET z!qut*UeMR$g&kvRh^iFzBI&P~JNs#YU%Fs&cv1}UtS|;5mX`@bJhWWbt8UqmRFJ@O zo|R=Ek^rF6$M8r>DZ}Sc6wFAx4T>wi=Q!j7W+l2pPLg}Gxs(6`MytzJOr6K&ru#5i$3j#z%QO58!tcK_y<8|^h)Re)lq zcHEke1J@!^3OiE>-I2xcz`1yg0{t;6`p)^&a4y{#unK-`r4jAvjI4=K!xPn;FN++4j6(_kr(5n6Rl^1x2*X38aJ?}#G}ed%*muii>U$B_bhcF(A zy6&;4NJIMOLnN08&X>?eXUGTfDjTEVI&I)_XeNi%VQ4O)2` ziiVMii9C7%4x!`5A7GX7{z%N@Xh$3OkzfD|5rQQkpR|^Cx6rjt_k7dx&`z#Jn+=!d zDEe?VqNSN?R*t`w%wav}tGhR9IFd{zW>9T~towyhoa>X^1ZhJ?w1`L}_A~wj#E=|) z_nLS`*6FY$+&n(u9cJ`f%y#kDUy-7LZHk+!5^-*VXA5*^<6L$H!1D58UL$lA`3yzO zPq*)kPnjQ0WPl{6Yq{KqW#;XgkV&!TvRW`DSM7c7+~dSz?a&8ji5Kl)8k-vshW4+B z0?`wgUmAio-0-iC7J13Z$(yi^Pv8g{&r61A#auIdrv{CWmpmxOd=gF`WSd+Lij=YW z1q57{fy+%Uf`bTOf#|b*w4xmE=jwskN%4b`x+h}N2Ge?WEj<3rNR{e2C%bpU$ZNg$36@V) z1z`O6o+#nL2NV(aJD71wDZ#607#`Sn4|*NLP#tZ2igSV?RXPFvg6{(Q&tq z3S!XZ9xq3rhH`7)L~LI!6!SI@<@*$toq<_twSXvGw6K)uzwe{`cOJr5`W-(Ab1?3% zxZ)5n@OSBB6{P)m*=jnySzz~asdjwbQUsq#k@bR!*^rcEKE4cLbA>6!@zsZU+mk0@ zi{tt)u^R0unV}zFU!8HG9N(#J_F4`!7Y?kVh24j?BS@LBv?;ym)@};PstgY+ zKSH)ezlqCzypFyIpi_}oGmlps91%PiIby4M$Ygyewc~AQgp-f zmJv$sYL8Gr1HwT7<91+RDOt|o7x64ZPH-H~qvWu&G1lzQNA7Y657;-eKNA<*{ysqc z*TicNk_Ir!DY6IZIE*Ti5od74!}Q5t5p3wHbh~{P0Oh7YXs~1;AtDuQiajr3%xzmJ zq1`%Oos~@*C%PT#s+RUZvJ&trn*SqUsg=yrMNF(f;%CK?4L|8VY4uL}jbu5lX$}{- z`H@R*+k6m2_8dJ=>U*lP_md3alSfOBO3=sQH3lR$o{t-p?`}oeP}0J&pQjbqd(7bB zbt{1YpS*(c3Z!pBdIPNSQ|q2BQz&XBIH400hm9FOrA547&XnK`YsF`@+y|c(R(AoV zQ|T<(W*Ke}w6U6P%f0qtEE#8-b9wJ-W@* z_qo)#UFZNAi@!e*8aQ{ylEx>synnC*27!(>h71lkc9GBcZ%9u1-h*8Hv0FVa6Shav z_nrowTH3GlgOJZYGoK8}fQr!{kbKY|3o8Slp=>t-hcCO|26PBfMEW^(_0s^Avb^>k z_EyWwXYyDwFxpO!(fB>OxY+plbGd{?ZCdC40mt~aTH*i_U?&OKc+`p9Q{pb}PX~c1 zltG;}>U}T0lKW!y=mxo7_C<=loV8pTeNe%V$x4s0qBo@;VEs{~>Q|KVUBQ!*?r?Q} zmgrcghDtwO8$k(4pD0FTF&R}3KScZM8Nq0IZ=~exR(T*{4nkRLn?w?kbf~Wbw%Mwe zu^DaknL7VrP!&icAq??K@@vq0i9$~`bm7+}41-D${&ZBPH%?^U?hGlLbTQa$m`b39 zD#;gaLX!#h_nnA-Ed`BPBj4!DRjLEj)TBb6oMID4ljE97!9my{pzfGW z)mZ~hAKphyc&lz?hErr*ylodnTq$D8SwJX?k4?5$5S_~XLpMRTyz~OklEzYF%A=y} zlkp|z`1cIiv6%FVFrrj`j{urgAi$04os`)LdDVB~inu?ZdNT+Y)LGW^$(xdC-ur@X*tIvTAc^ZQ*=p*_N z@yakul*fusc}zs*7SrMs6IYsT#%*_P6EaNs?&(>% zmcix~Pi#N^$5y}xIdGFUsTyUMz@*ATq~hW!W}8I{Om1$JL^BQzdLRlNAwCt}I3^l_ z-ir`ZTiIiGi9Mh=KZmd~W+%s@A%$-yB6W!%K~6>hrl_7>Fl8waNwB&n-SP;YOr;vd zqVSk>Fm(1@mm3|cTg4k($d9lk0?0=hI(QK(t|uNiQ`kTf)#W^2<=q6rV&FgoA%SYv zL(3}Lcj55ia%>3eCSNwA7wzH?%33uye4xE#j^`upm;_3bLr93Nm(3l5nex&k=pf>S z^rtoqa_x}kqOQj**DGEzOU@fnj(n5A>sESC9g)>Vc2!IIBjijuZOERia^ zqyr)0;YmUq?!&i~927+IJz7@-5R~9p+Bz>FKohZsE>?I~+x|F)ZUn*R6w~=@f9e&y zMB%Uf2^Y;}kN%xVF_r!D29t`5U5Bj0rPSc`&x`~FYwn3g7qDtK8i1$9hg)F$3vi^M5R`gG<=5s8Y3?*~Ap10bMF0}$~o#*hoN(XHydy*RZ-9PgYwJVaWPd&KPg2eT_q zT$&8oW)%j%>Dgw#y46~QR0+v+K{KRgF(5vh!sD{L#60cX>&1og-W%A|lZA<>SqcW_ zzU5aO$RfB<`Uxq8>a9HH8rtk!@!GowVro$~zN2#7`%{!H%Yy(d67BD-3ZFD;&9+!o zr>+7Y7pC3zaF=g27A^L*6rrgO0N;Cb7d;t+ zke>Y{JbDstFk{f=wK))1Zgn6!I#zw@%Cf0*ZBtX*fs2e5;V?@nVD^&3O(NpPA6`|# z8nEb21%Jx|^sB+<6tW21_-Rl$5K;D&d{;(Sb^_`~X>B8G8q|T}H>w)>4^6o-j ztT0+bZ}INS98A=G4%gKbNk%88m+ zy_E!R(;kjqNo789NHhi$GPhIs`5i=DKlsMx8u?#TSHOe*%!r#n_P-_6iiSByd>^< z{T=8N)9h!Bed7kMA;q28SdJo8OYP=Ir3YkQEp@pq6NBknz7nL$I$Gm5OAzh(lr_(? z@+K&ujOs&DbJ^YG1Frfqv*D99$&C6a_`P1OpR3oB6hoUjqSGfgQ4Ysp2QGb?`+|(x zLY~EtGiN^^)>5YHo{L}=it6tyBUN01?TF)zhF_C$E7(BFLm94()WrF@x%a`=BIRtu z%0a-oMQvXwp>$dDM&Fr}2;VO@%q`#HIjg+RJ5l1Dwx67Ht>ovu?)%zZ8O&mEP#H<{ z#foG!S3q^ri;1i^vP`6^4_?KPDMYeM1~l~}{l$lbt9g-p}9UC_eln{E6j6r5|VuPn=*E7Xj>Se4W5 z7FOa+7a?7n?gZC*0=IC+IYM>z&CAYMzOCwFcwcY*#FHfI*vQH~qo*)+J3UQlp;?Bo zt6pa8`1TEGx{2T(W~7wXfEBu5UYC61>Za6i)WMCHk%2qU|M8=K(oPtP^)q2s29eX) zbtvV@5MHZiH5^`VQ+PXzi`a?Jxy$mu$4i&-Mq3sYhn+YJ=a{#0uTVR}ToD_V;64AbB7T+03;4bvRH_^?Fy3;ZD}*Kv2_+3GDpK-Tx28 z78D4jgsL3#uT5nIBQ(d%#^PeRgFnBoWHTU>cec#c`jH$gZfZC@_Rw5D`P7BAjl`-Q zDq8Py%o1nxZJh)gZUw#>TAsY}URQEAJF%GrF5jEld(Sem&oCd%lh~ElSH}v}GSX{x zB9U@N#;1O@3{w1xstarGq=A5XRmk z1$7<-H0efhj6Q^aV%C3{$iYD7;u>P5RYG zCR6~M{;Vwe{~ICy?`VSQev-nZ2Q|LF_u~sUi(XHA$c0?PShp2FY`g4^)V=IBBdUNG zJOf0Zom|t-;d@1whFv;NCMd&&&!ZaP@T>3<5r&k;M76BCZx`Jb@Z*DLdWNbm$Q9rlXHX2Qdx=rjpY;Rlx zSlk@Zll@D%e$w+q6%`k7#EcoY@XA1|T8f<9je|kxQx01{NUAUo*{R)tFo5G&VZL1@5Wk(rv)*bhu&I3}X=U zZ=*}!F`syrE?13V)ubWiJgmRp{NGvfk5u@X#`#-e!Ib-F!5JgNC!b-X8kweBlZlm{ zm-{2u@=t#26o8y2n`5@ow<~2In^t3uC0$JoFbuA6FjcuYSQJ9Vr68uX`uHU=lSpMv z#^ATs(((i+JzmK?1}1xx%rBf2ur%D@?Zb*t-{yC!YiQ&f$;WM*{m$?Q>71gX2o}(6 zy*f-`XcRD>0F-=?>i^IYO#h4d!MR$H@SkpbZ`1;i2@$9OE$F|u#gzu2Nu#+BEHV71SooWq;QwZ!|FMP~B>WD9 zaReIvdi386r~{!x?B7%JFQ#?@$o2qdzmQ>W*?*fRyi0q)37mp|&kF#uC;(0^HHh9R z;x~f-V&e}Y`2UrS-8a$bMYH8G3k!}^q9V( zou*51a$*!xPW;osSzA#^x&A$)-h;2Yctu2!F*8w>K zrJG#=H|Ln7cljn_JN3PcgQllwI41}-y+k>xzlz8rRC-Y*QAjY2Wz(ZTV(enfsNu1p zyQLDBevR3S1A`jrR&aHeq{Ex;x@6b=B> zpA9{$Z`iAAHZfJPxj3BQzFPFz5q_9<>mR2N6tcmwf0#AfJ`(=6ASedrADeMIUSj`w zO-5O?Uyt7~+_{xCQjY@*w|PUo)fiO{JR7nynGGW{>AG=X&%7HM4Sydi^^1kj0sKo} z<}8Zly-nvn%dr+?oY+;Jvx~>Xa;P|=E3IDn>n1vNsfz@^L@7Ambu9j_JAf0e=Ag?# zjpFqrF>nN4wyPu6SsfBlbsS@GzkK$?GkxF`ccnEXd=pR+3$)y?abMpvmp#9(oTX_l znD-E}pHHi`+W1kJ9rc}eER>+TK5W@F_1jM*xzDXTMj3=ZfBvi-8K-v`d%)}Mp=Rkh zZayw))9Qym7(rca)=rV95EZ%Xn)T@6?)q)|!lr%2hH+~ z@;yX%-{0FYIc`Cz9D22=kiF9Sb_)UNwqNEB%z3)XigCYq+`!3mvvB=Ixo{yx#N77& zVip+5*B#P#Q@PkT`C(`yef943{q1eK>23$~^khS|H`}g}@oL31`4OEA@GkSZ=i1lP zMf|!8>-2BU5|R!qZnuEIun{W3Wm_{ho;QT%4t^t3C% z^0cEnek%NvLbf}LZTmsn91tw=MKycHGF?Vl_{qyp`oEewJZW&z8xZSl+P|zcTW)$Z zUTzl={NbVDmFrU_r0dwLGL0pDmHA^$z}%_v>1v)rjPT{=#>P6>kY>mGO4*^J2O{Zp zOe&_bMBitjX?T9e=QUb4*)YXlt@ap=iKW8IY$042{Z;iDb5$C$xpdn`&Rgu!{{ zy#oZ@Cf&g}r;WS@6nIK4G1LO0@K{gIIa?Be2R!l7C9kNaQ_zR)q;Ke8+=IO@rA(Sn zO-)lX(8-Lh0vl{5B^>JZf9`W3@?OI>Ma=u_s`z$(HlBXx_2s5Xy?>VBe$O}JtH$kV zYJvT$kD|_!Zgv9Pgt>es>UcM{>=s4qyD`M4BXG^zBB)V)H``l`mE2=41T&C< zAusP~x}>Zr$}#7-mH|qVflk@WEi_^Ib8h7l>!#*FH3naumlIF@NjSBh#~d%4ZuCX{ zXu~5HzlwdBtOA;=4+T2SKE(9gy%H7;1MYb2!Q{#A^-8p)D5pnhvRYm6b9>vnL)W@Z z@JiKAl28zTb-mI#rRX)PXwv>O6*j?rr~NeKVDWA0Q<4*E~0=fGp zO_yj&n5$lifnKR9^2{?S?ry1v2Dv=DY{?f1u-!qUzSbCVlEvsH7F4C-c2VHF!|MLg z?`UF(o|lJ}-|M3&g?iwNwQ_8G?RHbDdAX={x3>xFU4aegMA8I4)4z?kBLTR-=3BFfN8@aBoPyv?@2Hu z0I3^D?P+y!d01~mG800ZcP}P&gPW=-V+SIz%XK49p`OQKwiWN|yl1`F?!*s=t#aRZ zv$N)1E5zkym#8dJ)tu@c=+u}bW&N^{P6)-!$n7G6nz(+a07QY>)n4D@$f)KB^uyV# z0}kA}E)gSgD?%21kuvkNRsrjT$Dm1( zjaLP05e!;yHW{Qa_WX$3sh9cebtNH{eM_`y4?@9r=bP%HR~X0@!uI>+tBz<0EDBTv73 z9=qk$VZH=zC2BX=JKS=CQYIMlnsM=*Axj?TlRMZU*fjdH&w)FZ5z<w9^mXCE~q`IUhc|IFlqG2QD0YTXJ>9JzfNCs zSW7l5R0zCkLs7Ni{rluLwj!{o$MwTz!-9;c?0Aas*kqqm3u#_8d5a-nuDN`;gy3wE zq}gNqu7`Exg=H;3oiM>4GADI9c%n^mqt^I`#TdIkzY}0H??EZ#1;y`^*%y5}n^a2^ ziAMlUTBq{eis8MX1`@~ACRlEYTJ$`TJ?q^YaI`&AlM)f!h^|=Dw5N|Lk~Wa^iEye z@jN$KK0FUj^WC{WofF&^-yPfOUpD7JD2nryaWd07q7RiH&mZFXa5l{v?6T& zoxZt9%Ja7Fc}?fT^0~Q}#o0GcwB#TqkiHqA)^GGs4Zm{!Jl5LF3mz*&DF$FGI&XOn z8K$F>)Y*{!KjwNpGE6N}wtXh;8>*~bgpj?#W1f9I9=_?=#jSK158G6k5u(4#4{C$8 zi!IP8Q5YW#FS&P589tgn8o3?29GWpVxMe@?A9IeFj7sS&OWWS6o|{+k%QuHDITDCPs3q`g0$^Fn%uSJ%WlSb+L;o zWAQ_K5u+F>%eT>T9 zxVN`dhYyVRds^~BNZjzxJ>@>U?}QmdMz-_VaBr|Oq>@x0KWG0#FlM1oGT$2U!PK4p zn4r75NK4NmUmS6{h$s)q^WQc*Bj8pJsrfiJc=hDa?Z&)4FCnz*{r}AcFk)JkM*b0y zZaZ&i(Z6h;Hlb4nLpgz!GkOHNWqW%Fv0=$JAn>t{`YGSH%Nz8~ja-zuE6l0bQ@*s2CxtSRgXmXPe>R?^f#IluyEs#Pw&uqOy&lIjF0u#g$ooXZu?q| z%M|zq$NNHDtfcypdEVs@WF!~&8geMWZ8wy!K5Fdn^BgiuUtRPmh(+ct4^{xZtHG=` z$hu_CEwZyacCTY~P{HeQii-2RLAkXS66li;cza?UF8B6(=>AWC%xxYdbg0yqm}$T; zb!Lx4GEk>h6;ez~jGBNhk>2C8Mw!K1=J`$vo?2B*GL<6w1BBRR!YtTfufDk_7FiDz z&7$B#A5yu`LvKhKkrU**!nb-7u7_%=wUO!&1CqpKM7cNkgw(T=v zNVQ6t>s*D;Po_oEr*d&NBr&>vLbu_f}?ZtI;sC3lSL#}%Hu6lZ+I#-ej zMkS_AGV#(FSZ9Yy9hZObl5Fn7#`+8NNRC{x0gB$|s2l*CHyd7{ zTQY^L5@}T{?^)7RPMMfm=vcJ^idJfLAG0cmsmWVTM;kUN`^WmnAoB=QCBOV*fp@qU zzudo@=4b#;$#e7n|5xo3J)j;N_Z|5^26}71YxYrLuoa*q#az zQ@*e|sPg%*W{l`QXXq`-AoWzrIYq|$496*%H{}jpcYyP@qFQ-sYN~PO%jA`S^$F$Z zEc`06U=`SLwkKUOnk{QwkKxML%vqW$1p{L5Ie=TdKUV825b6Hu;(Eo0ZoCh)L#6O4 zwB}3%aIWd>kwpl)A{CmRbew$|1{IUVOz-4R-Tt0U5JdAlWBmHrV~89iIR{dlX# zMq~?!XCgXcVuaclhb|o?W{+MNbNeE)mm5PJeOzPho|VB+4~6BGyS*WR7B(BP`Pas} z9rW(({f+mGr6OW{7@j_yEAS^y26llo$YZ-?G+h`t9-`#Go1eUC{zkcFG1YDMgF}4u z%=btgxJ|P?CL=JuFJt9p%PULHdxpcY^0pv>`Wp%7Fc_K-q)ev?f7mQsgSIgE|Ps`pSzw&eUeX8j@g$_O)rS^pkqfcB(MkF@uQIVjJs zENjj_ZPwp`dUD(2>uBflqs9=u#7Z&DsX0t0Smtq=)oC!UIdJxEk9*|bB-ofQqKHGb zVM(&LUOe`#|LTZ^g?4|YT4MC0bAy77(k_V|J+tDmb2)4xF;^WrKbK>_e&@V*J~*@z z)E^%y0#O1oZZfmwpPtbX4n9xYDbRTJDp!aBAT<#kE3j9lOo(}; z>9_VjgINbeQwb37`ec`zGYy7g`tu~7{OXhD|pJQMnR796NyDRDrS zTAmWfI~Q^n`scD|8KLZp9K*GjFq_azQlI;j=H3L&MoSC^Flba1${NJsAjC$OL!-Gk zHVq)npJj~{J2dvJEO)JD1%Ja@MGud0Y!NOLqk3<^e4{b$RW9qq0?bwz2&QnT2*eMY zc4^Qy6Ly^Lr^;VqufW!zWIO?%P0&UJn^8*_i2SnD;4DHQPYn&FQ@vM9Yde3u6HCl) z0p9m0`IJr2IhmH-+4BS2eVS5eosXxjq;~ogtig6qaVVn2Vu*C()Q{I<8Fx?wZ1c?Rk#7peQ}x=c}##$Re$1Y zXM#vpP50-B1L)$5858du!`JMevx^@=ne6=}@W)!>x@Dc}gz|Eq(sVfU?0lj@d_w5F zn0Gt3&SwhHg|37U*E0tBZu7YSe}Xd2@oSspDPl|2OB9M(IE`YK+ToujmT==*JTOA# zKe>ZmydYN^R>nc8NNAiIaYAl^Y#=}k1t9h`de+%LKQH?;^Vws0a-34VF=eiLXcL1pEO(q{XKxt$?{ zgrA8L5;{q%B*7yX%&<75R!|Tu{=A2xA3~UtquX4Xu0r>!5k|#&XDv5S@fo~bLV;Fi zB25qNs;Mr2P8?Jv&Bn@JXbf;4eT`PDt(9wyXNaVrW4dNNWb{!t-}TquP2N2)vk68Z z6>3d?lm=%Jefu?FPCB4pAKtasfqaSMZg6=cxAKK)$5B2fPW9t`Ofs?B9HIpoxG`(h z6FwVb3>K`^9@Z-_HMI7k@*TB5pBGl9|zA(;2VzB0EJ z8wy%Ed3$udcR=-sPT)RZl}7urZ@w6;22s5bR636_oniBr@^5*I#OB>%Aw;+%7nwzGLRM zjz~tzTT~6q8Dr;t$61xhJP6E^sTMd2A!CQu>bWASDkWl6I3szI*h!k-oBcDd*R@%c`fW)~`6OBt5XS3+1<~Nj!3J6%&kzF=Mp5 znf&U{c`Slhu^ign2-BhO^+Wa9N}A_{a8Y_P_2+3gI!!j(kAtAar7T~KhfpQU>O^Jg zrk|hRk(zZ=82N0%WTTH&n+!N&CP-@c<4{rMuJ};7yCv+^e;5p{F~}ei!uL29yJjMV zY`kUl!OiDlC)SoW)y&RkP68#~~$(Fj>cHqCd#)Mxqjt10GrbcNw@NR80P;a#)La@Z2lzm?8p zz3d@CIed`$z9#(ZfOU<#OOVWOxma`KD)Gx4@;F~%b^D;53RsSv4+eEp2n7N+UE3H9Yk(O>#Z9AMa9rkbU@M5{#@{qZ;4%$7PlPoG>bT^=43X093!`*dOBMh-IF@G1biE@=H&7F5-UEwk$K zE^qpf1s8BNN;OUG^N8+=)zs>5$Z4A0mXelzpy(IbL6DL4NE`wV?JCE{ye`83q^u^< zL|)ko!A=czxWTyp(&!^sr#R^Zz_ zG2%jZ?~*GyR_$$5hFi5C_wX@a(T1k$ID?t?>O;;$oH&)?yZUv%`qAf*l3|fex#zR8 zaVj-)DlL6jkD>mSQJpe3lro|!%c{%a>oKJ7T4*H2lhoj6Ro`#b?-J=QC%!^|+Ne)T zJ+OmPh=}oK*u84rE`PozHrQM{S$$-%#%nmg3UbxDNd_C~hvIQw+Vj%4Stg(T2v{L5 zl^T@{7>dZq_CnA4ZAhF&Tib{9lE-n*7)+Tjr)I8)QkHn z>YusAf4SQy9>5FmFzW{KAIvKh1Dvcl@pbj)2a(&-mwh|HABq03gBqY_q-Z#Eww9Ww zC*MJ?sB(GV5rF^ci#~t~&kp1O_LC*UgtW9*2TC3hugk!usS~y}p?L6g=l6fbEk(#I z_{^=2lycBj0@nqrtE(5TNgXs$0b0E?PlSGk%Iyaa9_*hsLUxvZf3C5t@cEBJVDvbk zX(}<)%nx-c9K1<)Z>BNEY4&xWBLDzgnrsZ*)j23H@1N}O>`5@yTs#i$BURH`7B%v< zTs*3#vo6))ld^|J2;Jj1NUy7@9%~umCGCNzpPLxO*NlX@mqKdfW!D1lGc_U7=o6MN zOx#9CDcoL=-VuINUw8R}-bJ*@_v@(K{?|H#qQPg3aLX*+qj~cRG{SF#ayTp|GBu9CUm`j zcBCPpbl70~;y{tmzKexZm`Cg1{$7;?blnu5&uRxNR5SbknyWNnDQ7O$5~|M_dc;8% z6uuteHvokNR-Hf#mxfFHl>U365qhV2TbaQ%k0foVT3+@fwz=oyCf_Q<_k%;}>+QqF zZrvTcgqPXybCNcX36@L?0z33j33M+bZ~R`#_5l<7MI#U(jDg z(9HYK)exmXHR(+#xP3Pp$wNJ@ky7P82vdQtjZ0d5s)7LS^A$bYU8`3FVFmZm z?C+wgw@rB6w8zPnPbq)hP3z)`FBjRu`n&fKGNY^eFr7PUJs(%)mokW}956>~XP1?CmA!e7nY3pi(1E?L;I|;%<`l@x<0uAc&A7n5l158mvq6>_81uRO~`Ni>8(gK9@H+D9opy`)1!q-9+ z&`c9gRD+ot3fpciBs`unD_rq!n6l2gNZC5a-Nk8`cbi+{e$+0>g&Tw`-kFWUns|L6 zS)3(%dZ}`*Hx|&=va4F!VQca4tcf7ZH~zQ|s+4h~Ov5RpQAOJ{CC=4h=o20!;JB-( zi*!m76u3O(*zpR;OwlgHGr50`=2=GCfIUiVagl}O5v?|Exa> z96{!y#NrRDo&Z9t_;5j8s_#AE>HwXBzy{$>Te`qLLaYp6Pv>{xb+a)aRQz2-mvd!1 z=6@z8KKQ5Nk1>rz@QO$|sa3Yzk|W!yO3fPKLb0Er9J7LVj>YeGvWdr=1m>kIXux@A zP1R&?PHN1Gvj;_1+1duESAyGVJR6)iA%V?EnDL0TeN+2xkB{I>|GYt?Qx}Dc(5}5x z2?KBFV6i@O@?e7Y4Hdoks8vy6XkJ<0iJ}uW=g#W1F_j)RI~&Z`^t? zuHaNDxUELcg3-YjAiz;R&U3P%V`Jv~91%eevkKkpxavLIK7V)=fS8HC*#=qa<#a}J z7jVuN0vKdak=HqTfdDNjWkV!%qpiG0rm_9kN4cQ_mdPo7Mz;P9)W;0~g>*W?tWyM; zfen{IF`GJ}JV89I41{?;1VCKdbf4}^KXW$PxFA=mYvW|0dp$EI?3}@p;SPUOJBElw zo~7fQ46@!?wz2^R6L8LC5Vmn;-SplS4N2_CgWNzx_TX4(?3y~y2o7z_87{FhXu~?7 z1sjrX690;>tZg}Sw%jIfRnBpntAE5p_CtP?FL9uRmSa%^KP0!Ht%UFACdWtbw*BqysEY@&q6sQxCsGtk@Z zGN0xR`1v>Id$>gq){XpCCNsx}=?O#gq5Op^<5L^pYI5I+)G?$_#2ybGcveu#E_`qo zU8b%9&GpnGnoG-Mn6yc9Da>9%^`UdeWu}RH)PP(Pl=%;&-dwC>G6&G)OR|< zAIHr^CW!oOScxSV}=7mRQmsGtH7gblIqL@oLuBV`>zU}Y8E{AMyLBDN8>1mwYQa}stcl4amoVREV&IpI&b>*a>-m%Ni>3=KZyjb;G%FTIYb|rB9zuncVi#T1<<6wY zG~&6!mbAP9V4c6s&;&xa6*G~DID|`ecn1PBTU^9)zfClBqR#v0)eQ}e-K@HeZyZ1~ z$cD~vc(*dLxsU5k`yQgaV)SBGTKV$nktO}KytCoBz1>5vOtG-p`<9=4Et zM4z}cCZ;T)aC(~Q?~R-$2fN>4w(uRF$-%HfT&!o*hYLAt(`qz~%WLa#siF|=PgLs>IOErc0nx-lQIkbj%9m6apQwrjY@Wh1g_OCRtdt8?3qnK<&yVRVzo;VtLT z(Mq$DslVyX7l`8Rr*!>9LNijm-s~<)rqJ1W=-5a0gqQ&--<#{6|9n;(e*5>H<*>#oO-yk$LQj`*|hB$XiJAJZ42hTb5+NU zqZLxV-KW|`KzWJaLXeGvnG`mW&@1d=A|x1SvYDq9#By>7SY{0#H8XRmT%iF?l|RhP zw|UCi@8LWz>r@ZUgOzVPa4HyNMekZ2ieZ2s=a+YW7P>N&71OxhAgPWoH0T&DcbFT{ z;(Acb0emgO-A6QNV#;P3e)wRFMin2U!A?Nb^y$$4iY&1Rb)UPF(p>AOymOpzvi0{| z-t7*s!+QsC*VShYhnp>Lfj`u+1@X38vHRedgHZ7nQ*aXWhIM&+g~6`IuVRL$UWQP1 z{Bi@tT#`9p7Q598vVCT%*WOCEvDYQTBJ(MKqZ16(%+NnYsEY9cICLMR6ADg#@kV-}~VvRr%B^ z5$U2}`%uc1F6PGtACK5{i$kQX{b2Oj=r{SodqlMmf#EfMwBbXu4jj8qm;&MaEHlGu zHF0B=pb5XB2Q%hiS$b_^YcMAu9Yx#HNytm+Wp1%M?Ixzy$xb*lokmoZECW<0rP(O4 zSptf+N&U@fxeKKX8wD)Vv($QoP{72w4CQCTCWsifvib{n7m1fbY(N!zFa(@GDqP}t z{)mmoH2h@HQDvosgS&BY7L}LGt!zZ;_u(~1X!BQ7#bH12J``adLYCS?y^Y%96I+q% zk0J*vv5jxycl*Wg(JhkKe|lP95GbxbNuT!ys=Wd*LT6<=(xy}qnsPhf?mNzh(6(om zYzxlKxd_dJy1w1yndNf6hP-7v?2yMA5dFiZpo)uI@bgva$JVB6VwmSO&%IJRaVx`1 zMRRs)OO{(i@|16K%7#Yn_rulHR^rBYXo^rY1wL7P)pgCtv2lqd$b|WH5rogxs(^A+ z!QC|Y6WKUrw?B7mmi9)jf8YTrc(}#Wg~~4RW7SBcPi3{lZ$X82KZ|R@_u2TjsVsKC zjdKy|t?-;_6V_v_sIMp5vdG&-&zmODdqCW8yj=ecx$C~;a|GCtgE1@?iJF)Z`Nw57 zO~gs?O!E%44774*S&J@s=x#|?omcz2Mi-yv%-5iWF!ffnwdt%9yO*hrkas7|pY2c! z4#q=;Ew6>^RmW(Gh8TMF?%+;uw(F(d7ReK*O59t5CmnmhhYq;eu5rmLMvygZ7qS8XL^VT-PCu~ormsS91|&i#ZsA+BII!ozAb$Bi)9Jet>Hr1&=@lp zT$hxNx73wJkMBXqgOE^Rmw z%`FP#J>Jfp1f?uTRdBF00!S)A`nzXo`x%prr_@ZfXTcAjZrSuicN|L09wjPCRDqiy#9cKDxqJmpMfBRgGtD!{`*6 zO1XL!{3W?MwGAdVdtRA8#q|OL;k03!THH*68mspH0f*+bv7PR`rOaj=ka^)v0@@(< zxO^vOap}r8He-c4PXfC5l#Q(Us#LIQIKtDeOUL5e!*RytL+nrAWr9|H8``>G-ADH5 zGuV20Ha=&UIY1rc(=;QWF?{HI6g|1#V421GY{e_-+(VoeIrH?V1)77kRxxwtU=A2P z)DeH_v{to=UD--Oc2Lq|4$5Kx``TXjyNg+uHofFBdl5UtaYdPPxG{2uEK-8TInd%A zy-6<6q4Xzq6KfcHe~9=xwqpo`IbpG4!Ztjcp9I9#D}C)$OSK2;)MdNA3HwO>vM$52 zCtQM-5|(=MSJkc?xDazTVpXeFS{1Ixhe7!_Z!2>V2Ah8+O+ul@d#*@>N)q3m7hl!I z+$Xr!wClN2+|KdgUit#h4xkC=V@yJw0L=6A`UxNGAn*{Vei$y|ZxEw|TL3ifWs}pc zSK@BGnkd1D20R`2!-a^f7oeXYN!)YGq)#6yGewD4Q8nvwZp@wF9?imqniw%RXlC+FZH#a8c=_| zpX3k+&Jda=75N6#pX4hR{-OM>$n}R!k2IobQ)gbZ$e)Up=Y$IeafpPU`5Uh9!^S~& zKYoA@wTjknh=Ph(?CPdQZJ5(g7`CuQupUlkL=Gn`^CA znF553VGv#WuyDc%PA=awnCcU~4H}Yf94}md#=cXYinT3MFp`hA*17#FQCj2|sJw-I zg*{05$VktI-$MVRjLUg}Lq*}Y8v@3kP ztg>I}hN07gKkvDdhae~9InehcnLdv>RJS+4@ZjX|Ttyb%t~m<}oE=EBna`jmv-s3r zpKVc0;_7N%_qt)*y9`!e#p@-t1x&S-VXDU!SQo}FO_$$z0>-<*5Qarb}~g?ry@p6(0Rb>MJgL-wD$F8MQ14a7^{s(#S{ z>Fd9xhLZGvq2?iaLx4GI#I`bH=-`eP2tR2^^P=jX>QOica5e^9S}o6d9-cz2 zmTfU;J3Vm0PcqwxgO==cIg@jEOw15AFMANAR-M=fZTuSf@uX(b%gllz*ty4+nCmBd zz@f(@`c98NS#!IvUGoy@Q+F`tj!qD3F z97mQz&ID+o5^dv6lmnrp(xg}(V7cCT*Z(d;MCrY3Q9*_gI^Sn?D_qI<^N)xFpdES3 zN%L>RdoLG(Fk$#_-IyXz?oT_*H`&^uLTt1Hv5U?IESJAA+D-EnnXe@bfT)KpUu!;S z{^ZzW)^+*s?_xacerew+a3y=5#jvT3Jj`CIpRFr-xvBg4frTINqb2N<+BaxYRVDiFgFOq#OPAZ!6dSXa9e?!vUctPy1jLGElzDZvm`+B=pM!&%yf9%udpT z4Zf+-g#p#m-r5>FF;j0>Htd8m>SO^ zmVe6=2Go+p|K(R%TcDq!EJ{k_1`xjsJt7}^H-qvs7%aW}Qw07VVJe6A=Lj>3Wp?gE zOZr0ZeYv?29OFM>xL?KD|3@jnU*|T$XqVWY`fXk`EQj15Iva|pK5MZWfz!XWyzVZ4>^x z+5hSld&0zX=^G5J{8k61fs0=Mkqj)vM}d$N3ysJQzArBypZnUGnS|$_?5)d)v=Fh+ z9wUdPg;Pjh)3=%ey?&aO6gcB4!oC)!=68e8HHA4Ph7Zen0g zTT*i7OrP*_L3M8Ft-kYAjsP-ycdQH-+txB^`tJTbXUAx3WRwWGeHFJ#@eOXN*|lx( zbD0Q0d6c^j7d@4OfmEeMuJRpdfvR*(M`ec8R;>`35MBR%+tM&>tf5TU&D5S6hLtOlgKo76TMJG$v~e6+57T|Np3)@cXO&MBBJWH0|Q-?qhx zx9#A}Ug8^wcXBv*OA4gqPgmV|+U<;0?YDRi9JoUy3WPV8m zHdX~|p=Fcg+MxpGgxKAYhumH6C$8S-4Md)Me&R@h*nADdY_B0!hIFaacT?0Ww%;*c z58AEU$Aqex(|lO+$DFmlXY&fwS{u5+3pg~JQOfgG4v~V$JR3bAum({+ivN|ngEXTO zGQDoDZ%p|1cj(DJh!*f_y2>Zb6UquRukso-3=Dc{$|hyo5^D63l|sU+FyyF9*)%B) zmlhR)x2zld_E~wrkOD&i_Sx4kR8?3y!$;x2Gj9w$W;t@Lw)FK^e^PZFp*Q3sokP$6 z$pYE6y`Voz=~-?W@9Rl!Z@~TcOA!9DYI>B$Ehq1tj`5N{7dF|eVg1YI6UVEFX3-Q$ ztg=(uWYzPtiiT?~VM;Sb>x~JJZh=d(t!=0~_ss=2>n?&BS!*U{f&v1( z&lXxak`x^=ex9J_wDCIYb0=37jXht~>*ts^wp7&-OPX)*_9~(U5xX6-v&#ip@%w(v zc-8efKd)^}e?k^@4OBiCui80DoDfP--*Qd|K!i7G8JAF0)aU*EnBwQtGyvLl;*qu@ zKq}`bI+0GZjq!j2O3cq_JBNU4Rw2uIPtsl-Iu-+m;ER8jk^AGL0*)oM{k6 zpnCe5OUtZ0GxXrEPLrn2cObITZ6eY+QsVAyp+EY#B@kMYEQjvVi`N51-rYsY(*-4; zv2rXvd9=G-Ws+?%?@2OjzuY^O1!+E#Bz&F`Vdmep6e5sl^1@;)>>(bxLOMP+9>(UO zXvVXNF|8umA)~yyJFf?7r*8_BstlNg^t5z2%pf#{U!7JDwhc!0WC|UXskQ$224lSF zO)#2bQ9hv}i6*{7IbtG;^0RaOxNIV>Jd`}^)6k-%EbG*>=zi7pSH#=Znyw&1`k42a zBdh~p2=>1|T-_|TrCyevto3abrN!D(?9;*P_1?5SOjpHFN(Tx}Bk(J@n+f{=dARwF zL$>|)DeI)iocqX5zwf!PIz)dW1XcRG)UwvBJoNTH` zbz*&g$FQlbP#Br;K>u($19lVpMo6d9=DI-4-d2I`gqMgnUWl8B_)v+JxN5cFn{4aH z6r|Mb82D;UEq62Dk$t_ZtsKRbBBlivyS#8BCey#RHE^SZHU`QP0v-Sn56D=m>bq@R z7eKAMn{$fn+x>trc-3>F&X^8}C>~aUlm0&$2LR`9-R^Ac+~-7nT}M7VRd!iqDE|Qm z48Jxkhu_|vOX!*mL<^Z(`1ozBA^#<7;L4&h&BTtN@nrh%^lU&_F@VvsEiNN_rcCc%MB}a6gMT01h@6L z-RWZuhNLn%QO?Q2^-I4J84%m7)_U6ThhP+cQ8aLmBEFCw;BkCe{^Jk-dmHDU6ouk#C5Q7v}q=}4_ zPzpo|$x%?ka8%d@XQ@V4y>DFNguHeQzbF#YEdPfSSM>Jxz%t**p|>pA)_0o(kDMX; z!hf)T)oFidvG8n%SRHb+nEep`3o2#0aj+e6gO5A$^Fu@#gmZlAH2jrmmF~<6C~1VB z>d%a>&5b#1L%^BuS$Z{J2Q1_#)W7tTclV|4E-;!rb$&?%vO5DrzdqT)!6QFytX1~s zHB|U?^+<@A`;jDM3 z`)dl$vV|#ZP$m})-?q}%O1TjuQd9+=ovh>mV$O4zplnW=f=Hc}9Ffkwxs6I1dDGk% zA8T}e1o;K7=M|%bVe>C$RJf=Hc4=pI1#Ln*q`4by&bGk`)ZwmL{rA>!Lu@Q9=gF!N zHG5R-^#J9I@hLCP{z1}wuG~;H(tokN5VY&1%yPl)x|Tumz1Cv$BYa!xc3CDM=2b;j$7qCJ|JS}i#a zaq@p4P{?+z2s#z#J-%GvK`PR`*7ars>)?Ax9$Zd{FW=o?mh*0Fi3N8l2}6&c7gxQXeiQ{TR2Z^A_0Yxd}R3NM~;d40z!5 zm?&DH(2J9CuNt_h`vDb{jYy3*=9QqIH!BswxTk?=5Iq!2pE4$W7tp{(_SIO|IbW90 z!_(=?zOzY2`uFg%2+CH~XEc~3+qChmO1HI=hNNybe7F(p6AIY>4LD!WX^YS4-KKtFi$B?_Tlev#?ku6gPgbKtd!>i)i)i-G068*2y54!|fXNA}a zakzX}GMuFv;NpXbvSKwuM-exr-|nhEwcKMpKah86u0(5f1)f~md|}CARwHW~hbI{5 zeL-yx+^ccp?QvI;fA(?Q;)mr2)p>=fVq2`YYw}GVQcR4$ig^e4YWjs&qoIca~gzV9p#4Poe^OK5XY1~0IbO;ufPT>w1scTtReH@1K6 z{?JjcaJh%T?zuCF9ABEQs^z21OK3!2cN+l$bO?k0NJ456oaIb*FOqPY=)#wzlf6Ew zy8{}L9@oFqeg@tN-90Rw1xLE#BRjh)D~)e{tB)PO@bila6X@R4#wiKtryAHY5g+9> z!GHCZ90{}j*?`uZJGSGkvP{3izGjLyVU(W9+QW_aXy{fFd=Bpn`9x&gD3+B7k9@j` zuDm>(1G|1FdW&wP>ZPOP3-w_Ckd0;BPPQq_qZF-eGe0r}o)cA#y`e1RsbXX@Z>Y2s z_}V||8%Jh%{N1N=$zFsvQXW$bcJl}V~^+rLEz zqZ~vBH0X?UCqhQevwlZ?vTu0V+*{%{^3O<9TP7ClAECuZSI)S0!0N7<9e21%fp`24 z^XQq$kVlQ(MW)Y*)LPvVw|tw#%HIzHpPk`@-JGn zLp*a{RcLQ*lJEVH9cc^WaushKh%$fl%eL77#E{Ov3CF$NrE9ReuoJT&H)cgk&wjWf zHT%<4)YB@Pkm_Q4@gby4kki_qdMZP1z}n%=B~05M&w7E#XK7{~H!u2>$`!+44si;7 zTh_IplvT|bjbZrg66*3;^-9RkC&yJd>~hmNB-V=I+=4j)sU2B4o7S{1-Sf^L7SfQt z!}lIpOPXzwAk@89^)qz4v5bNc8*#%DOhYoy86J8ExU!Y_o(7@rwDMYMK-C9apz2qk zE&b1@ZXtXNkQ3s!$(|U$KFRTN=>wQEqUP+tIYEX)jfUMd1=>4j*eAb3^NzBI_P;ft zr|RQjcLP6AN}N^@Ik8xLWliD+;TL$EEIWL|Y#Dlg3d#m&?_C=s=j-u-J)-acklpF$FvazlJ>DNS5tYd>!5c9cv}nq~7sK4zWlk{?Fg za^&h8wt*&t*Ve~#5&Z8@XtGNB&)9m$Y66xED_9=|L+;+2;+vLZ^ts53-QQo|&Wn$* z(m-9x*W30v{r72)VZRbwuqx2$GM6^dAJ1LJD)R1Gah{QP9&!f_Nmc86z-Md1tM5YS z@Kw(CG^ujz$FOBI@>N8)CH&VWPoIHw+%DQdEPkkh7S~N4JD)+3ZEMkkMu(Ih;?MrL zd7Fn=llYueXr3#n%=7vlSD(?x@6U$Qia+kY^#vq-8>>7wr0+&av(s$kkKu~@VI@Qw z1fTY@Ng{0(F5x`fW}G2#+~>%sK9i(cLv#8OBl#3#1Ah{D#P-QY!Ncmdc9zPVHou!Y z?J<{kUk`gGwbR!~<*LQ?ZII($YNLn(L0-A`)%GZZrp7*t#VIS)!k<1|6^I~B5#U)5 zJ`F8&$WC96DE}K~Cf_~_zf36TD6VD;ZEd|-{xC9C@w2%Crcd?Pk?^Aq(d{L$CWCiB zgfB5>I$^v_3r#B0nZ(Yo72Hz-<0zsF&7S5>f{at@(^!^D<1R-|UlT9O=ym@JYHmBp zj2$mSDm7`SJ-OqP+!$Y+0HgMig1Kmql2MsG1x1rr)Z!pwfAp6iD`I9`oi-KaqjZ`-&seo z(VCG!s-PLOQPq;oqxC5p$gHuH6fz>!RrNIXe{%u!oUf7|UBw3!;dbnk!MCPz%$y=M zpBL)N`AwRX-!FK9f3!d%1<3fBegqBspWenxj2TVc7$dw7gI2c|pNyf_Wv*i0rk~LN zQbs1+4>PbPmoTYv3dYP8_ssmm-u;Z3k{1}>GE7ZO7xDezTM3g#;Z}L^xi?_RN1O}% zgP<>NhD_ShP$x%xn)8Ql8@@lC~ zRVQ?t%AJLH(5`0GYe5?c#?RmWD3fAKDToSOw+2=Zxo!}#BL0z_9XQ4 zs>t<4ISK7_sdo)F#SBfhLL!RApa>uevEzE9NKSn!XiP_$+eT^fGB+28M<#C zwxjTUasD#`<$f|wx?g@EWuu)N&-7bL>Akd;1AGq{kRI9q@)n3Fusry=;jJU*fn1<& zgZZ-myre0>4cO}MOfUZvz;X8Lb@pk7(bTGCj=xPl`xy2PpiWeA2Q?g2m;mYI0YKMl zE_jgs#?<@8t>Olh1`n1@&jWn{D7$5%CaiR9EDdi0L}~-rbwb(I%?(|0+3~;e#(y-0 zhzjumAejA2VPSNcb>ki4`ect&IuI`Lbptn;r^kQtpBzB@Ngd7RNTz_2AjrT+r~M;w z?gwmyF*)YdnUl~YF8+Ve`G5jTx5q26xiUldF@02%=+2S9`_cbgzfgTH2an_W=W5`- zqZl|DY?%M8dba&=3g#P6J-Pp>;Be;fK;U!#OGVlLae#3@a)yEHqvb(BzyHFt(1EuD zU+o7dA^6j+BlFglsML|Kycyrjr@z_Mo z+ocR&@0J!R!R`b%nYj>bp}*=*=rMNBQBd%C?t~9<*Gd>xBmmidFx!hpDuARH~cb2>CPbc=H8X!?bwNJ$`(Wx4(_MuhL z5HLaI6pvzTIB3uG$n2EQmkH?_dQejz8x^T&s;g8&Me#we+3CEL6?ePui;^4}PBH zzE}WO$eD zhrND}nAzr_jMc@a^ggU0rovwMV9~lW_VodU#DIr>1_O+NeDp)*`nrMnJSKR~h+cW* zXIFDWj8dt#sc1pk(>L8-_s(+c*85^QjSSRyb%gwl_mdK=18D9fDx8)25-ZW}*|^SU zVq#JrfF1t;7|7j$aOZu>oUdLXBq0n~aYq3gyCCqd*G0Y4ln9`2|5uMQe9hA2-142Z z-`O&Vn7oqNaKoOI8+D08oMx(X^f)&z7@dCQu0L7vo!wN(y3C<3^yUVgHz~(3D0a=! zYb;K`K5%ylgWUnv3`_`f0P9Nt{wu{NZILwFOqh_|x6ggIL|Y0P|9`K zn`}ZS_X+uZ{ zG7$QrZlB|q;b^N>xjmUwKN`t-dHtN_^4q36nE{??ty6Qxfuz@dnKn|x1$g1Cf;%f- zX_?&Hzu(0jcMlGz^_(1h(+navBcb~lAq=3Tp{q}SynPx9c%Eao`!zK5RhB>R^PTk2 zt)Jcnr|neC1SEQ#?-vy3+^f-Qi@})zh3YWZgSIZKZel`4Kc;n zUbFv@`C7wzDPZ4t-*8lwtKm`~kgaLDCzE6}E(3#gmf<#cF#&rZRDJ)T0#*%cP8u%8 z8}f!uqk)(X8;J?iGOLf;h>lQyfB&OGD)NAGe0tv`={gtcb*yeKo{pXhYektP2a7=8 zPgJGdI+x1Z{`zuGLFh5hN{Cf%h zDyD+4gO^xBq-+E0PkK5eds4vxd32 zLQYjC9~tOx=q*XOgFzO1BqM)cGv?k>)jfN3B?oe{32x<3({;V*(?crbir2g6;H+_k zq1@rY9#-R;v?R1?vljTHHKbw8i{=!7+je3TbSIQ+4Mz%VeZ8jwBc;Q)Q)`EVLnMo* z&#j)xKqazSC!aMd+zvu`_?I*iV5?>Z2*r%RICR!Hw#cFT$>%JsKd!O2O@`(U6`P>1 zEsLNhk`P@rMe~t89-Eqz8p6NGs*JR44f+rXzY0pc@Svi0Dx@b9h_3eQ0U)mnU#n2y z#1r6m#XwlPh@Kp)4H#RUq_m6mg1QYA7=Tuw^;G5=$bVJTMc;_~hs|07E#&@Bdtd$t z_4@WdCZbU(kv7XY5}~x=9AYR-kuBL0BSP6rcC#R-#mThTB1V**vF~O`Qg&I!m@*<+ zW*FPdFzfg2^E{vDiSrLU-{<@FgCESim-}+x*LC05>vg@Zf~H~W@V;){0zH0LzlWOy zswPkX{iN!?)xGi8^4;c#@+Tjr!KV)htv-1x{Bz*wy4RDB-6#9Iq7Wv#chYkAa=3%` z0tjOp%SL}uolLtuIGBHNqG~8i)_NR=oy*8UFqhw6)Km}{yGlfNo#Yfohjt$e{YJ_k zYZ+xQ;;P6eWfLM?@b_Xnf|_(GE-y=N)`5BYqp%4Fu)^-$i$tndO~7Tpzb=$f<3pw& z$0Xdc&#Cf|S@V49xpUAW*dxlM!|U-l)Nc+@V5q6+(dq<>F-#i9qeZ_YAd$m()8vyH zVavC)0SIBh6vTap#BJ2+lun|dV@7`;xCsc|Tv6NkH_l!j1pYuO%&8?{l0sT7l@!xD{ zSK6qMWnubo7pPkzG$fu#SQwaU@(eB$-w)&DiHmDh>l1h%ZdI(v_R;6Gk`2N7xr}6) zl0G;x4@(r|Tha7qioAz$YSQ=dX+cc{v?lwrN@`oC+iA*gHcBy2-d{*rF4LfSyd`EH zP~b3c!I4L2`m>7x`JP~a%{~ffBY0Zpnwz0Pufu-6I(|B!PhXe_R6V(EFtB|`EALbz znsAn3<^N^Ve_0o3lhGdCiC8+m+Q3SmTX7QlSh0UP8YzarW5+qsur&C@w1*}%F?(^G z|E@;;4F4G;_3&&$T$z3{T@uH|5#6q10QbA&&}}KC=_Dd z(bHV|&=M^q+VS{dg#Ld=2~d=+T&5+KBPA;cn~f@s9;NV(Gl!9Q3QuSC0&cSF^_r`c*-@`WbFS;i3Kb<5DEO19PgT`b}A81OBr}tyG zD?P$!*pVQ(_VhfS=kWl3664`3ZsCh<1zz%rKDE}DAMC1^K?>`~o-9SP(z8FbT!ZU| zHxk_-)p!(-Mo`9sDCz%+ScBQDOsxlelLQPIG$~Pq#T$g2}9DcfR^2n%x5F(hU2e z-+n&O^3AQNUcF0k4E1N};^HuCE_PN2j2Wow;gu4@+EY#p`8+UPAjF9XdsU-G4fJT= zOVJDXd~cb40`*I~O(qw?8xx?@T7XyyK?$$HS*w?2YgT6Y06F8WzhBiF6@u1NRJ34bzE&`l=oIjB)%Uj5_wGO zE&D7Vv!0zZBlf9DB~wdwuu#$QT`(^RX^pqQdok`l<*4D$v~d{CapA9Tz8G63o1!H` z4;ylb0qWHR?~66h#l^hu%j%kr$Lw(s?zp{lR4@3gE|@#&cRHf6)VCTlI%*xid6}f@ zrBw|9Wtd;Td$08OK6wHuEV!Oz^b-E0GFjcum|BU=n6njgKA$#p@mlf*QELRBuA^ zws+%tckR!WnxD^)e;7Qx3df9LiQC$bTa`8#4g04Ta@|cd^3wTNGLOs27NQX8!)UDK z3%#kc!!zgSu-DHD2HW)^uE;)}qa2xBxg2xSWZ+1_kG4ps0SN_($UhCH=L#rcCh(Ne z`8OKvULTvawfOt$)sVSSz2b{BMFpcWJ;w>_g28}~Z1KCkTxif?jk+lk6tZ3$>2Ru_U-%uNmedKg6XIS5~jrX)ws zn`K(x4|rh2mF%*kSnuN$j=bEVYsl*jAHXS!X&tXE=@2HQODf>sJ!o}=aI}wi_L*_f zu*`57P9cUDjzKY}dKcMw+>6d7jIrK*ruRsQBFqbcvyxrpoCi^|OpNfg?S0ja=+=9W5rUq915V(?4g1V(-P z9e4^D^`{Ww{b($Aa>&#BI^RbY!88$fHLDB8$9Z{%+PbOkzdyOwAm905QbkHU=w`^FT@Zl-IpIJhL+V;`tGBChWJhiMt-z%n_n<9(v1) zfq>nggFamdM}^nw9;V;JU)p&Kt+`%p+~0O)PgNpNNu=$Fw}%E%Tlax{)kWp_4-6Nk zV%rw-NB%s1aq~MV?T9Kj1$`J?eZo0QQFwFXnAG0t4?Oqf*n5Zn`|txe?*hS&lLF(} zJl#Gg3T4%Ch(JPVst{hJSoNc74D5dWDoW2=T&Y121;~s)NWD2Xyh=-nFx>pmk$AoH z!%gX4M~pWAT@MtMq^bwbR6s`D(BAxC1A(=b^uR8{Z}R@yYzvg0>3%tZz883%66yas z@&CtdqogI|1WIEpuWcE#UZ#R*!Zol<1;4K`soN0IiY--bfRPvsT*~|4GFi%dhSdUP z4O?pd9Y=o2pEfNT2>$6D@)mm`?F6fXi7|iir$uG{@m>tj+9WeQxxLDOPjWPd#Zqod zO%b^xj35?ve_Y-)e6U)&{r#V0x7WdOL9133Cl?=esJ90V+h?gV;)=7)eZBo(Hubo| z-)gO|ghPq^3Hw#dH*!`{5_@!P{fRUhA<91?S=^9LD_eA)U}a-VA9L@YAMi{d+_3(b z|1)JyO2&fwL!oB0hk*8un=Ff8wwF>tm)qyEKf!8}-IJ+Rk|ahwNg3^y?;K@z8b6~( z>gj|e{~<#T>_&VnE;aj(s64LPyAYASrqu?b zHHedUGwj>TsE7nfZ_EkOtNHi5is_NzvOkQg&3)MQBf*vVzS8sMWHVo`L0B=|oyRr8 zJJ;AZyf3FBd`VU5njNB~Hbhajb5ZtJ!V>IAp|7+#;{0gt{PhL6Bli}2BukC{+G)a` zL%Vl`DcFu#)59`)K zj`^g|s5PAYda_8CtDT@HN$V`f1a}sC*}i?qHUdCTGP8O|YWm_9RNu>2rsFz4HDy&CbSIUf< zqh?1Ig4)iN7^a7}b!5S{GS)-(OjT8VPBQ*R)ryxY83=naV$?Jv&uG=?FunQB!=~_X`uSh3e38Gpn{mHmnF133$J8S{LIeAMj^ylO& z;O3hqyK;45=X|$5SVW4)p>#K96HxE&7MI^xt+$_wMUxZb6__VUb7-d?l{NmWqwH5f-u~6DFRSHIzQ@M*Bd@#LC`&Ff6Q*MErw;eEQr|xB zD!IKxR?+--V(ecA0Sd2F#X(EOW)T*S(p~WjevB@!3SGzz&5!!SLE^Uy1v^|71a|kY z@`(*8O-trLBuO`%cxNtMQ)-kJRN*^u@TF0GF!Z6?Q+S3^ePsQw;UY?0Y9sy|^Q|r# za#S>K7u$PTJ)W#d>3lh*tU083uqH*6KYl^eXT-&qRBeV4GokmoyPY%~EJ@F}o9F(x zxiP7A*VV>51340F#*1W$9S^tH1!(=cKZ@Ef4+M4)W{DPsY~WNPdxhVY?_UW@7>oVu z=9$F#WAN)=#G~#T8ZKbMscfA!Mm3mU+bh!HhCe-=@%qzAv%5Xi^^so#S=6%B$eFp@ zvrNZ_X?0S;R$p3rEqYbqCbrNVQD_(`+UfdrsXT> zY|rZmc9XSyG=(uwA_WngJOO65-G#@q3|%fCkhiV0gN3OlMwH9xI`5hH?0J1>pW>A( zL5-?&AGGG$v^wC@re(nh1h&Gp4WbR`QBWW3GcN@Iq?77(fb8!)AfjAw+1>!U=^PA- zs)tmj3hF&@#mT&FkjeS<&6vxaaSd(>sIb`8Px~6uB~5Z_-+t>>R{RiPBb$5V43ueYhkB^!nnO}bFqwK^PE zMq?-PVIQ);q1w)uuJNS?63So12>(JXUgZezZ!Ri-qBJ z>9lrdINj#(nOl$GKjdZ00QDOpXMJV9tX;-5$gcRh&Dnjw1%2ECOT>eVJ%$@B<`|iz z7#{J^k|z4&^s8^{vL1?ap7W9G>+&8Lywl;BRR@2K(l0*o9zs8kJ&1VvwOZ4rr1>Yd zPnJ%w_Wy*vs(?AQAW%y{YuwSOgEU1pDL3Y#poZ+{E;B`N1&~JgHk&7`eqGi;|JT#x zPlIujB(G_+@;KzI(_kN&GCdDp@@BG^I}77qdNj|Zr~qfbd_%8#7!VSdKt(h!#3}9p1j=NIH8}c-!`i@B z0wA0R1B%H+0C-3=THcU~CQ-2X3>odvm2S=X?+<0GZ?^vRjt2z_CLC;R5>MEdHpib| zzSIC{HTe?D-5G$QlBU9ulG+IfVD^=(P%+ZbVAZyTiq>Yt;jMbY>5IlnGt0l{F) z%%P(oj*-r|Q`R2~t8YB~BNj`@mC%5Y;+0N7^5tR+e*^(}BzX|JjB|h~2<%tViq|9U z6X}#F#S&QjkGEG5=|uN^gXW4eS(%8$x!rw075FN9B8r}-m8-bZNNL2M)O}?g91;G8 zh?lt)Jf+yZ0PmnqKyPcjN8OM`oaCzxhI!0pY3Gr@&kcC)ygyVeyCMfKV9`HBCGQ%L z0OO5eS?T--7!0&w%{>f?KyIt5a3GQI%%kwiUD(OV%uGH=LBiS5N23lq z$BiT6zva7`94aDPOsBmIymklncsp|E_|!UU-&u)pl|@2TWAV{e3GAd~5@qt$-wP(^ zW-2TN8dFCLMOWKj9&*k_i|@JKYu)tzD2i<4DaN25eynmo{muwX1rz)1cSO~E7E-cs z`LO_W@I^A!4aAG&0vhva(VQC3#&obR=3r^)l4}DXDASFh)4tXPvLYuBlS=^>`{?=8 z~&F~Yg!8+8N<`!?h{29p&<{p#0`rJZ&& zGUI1}77q%-);sLJObYQ-gq-SUWS{MaCPRb!@&gxM=RbpP+JETj2wgV>H)HBx6BoZj zyzuI_QGpA07Y^0CLuz#n_Sv*BN}U4R;F34^3lbH9h-{RDe&g35ktfwr+H$^S!W^*Zvq(!7cuf9Q&i z>*50<#bkHrIParL1^u|g?LsZ7WaE>0K zQE!@~+3f|rartprXBSTQGR3B2+qKjaU({I*GaN1WC|_A&-|l`L=k*;zsiVw@#iRO% zZD#U9SCTxt{X$!Pq!lEqDIeOM=^l)y*>k@OwOcmmhIDR3FS9@>%HI$#;ccF znmovG`}rW;K*9n0Y7>2Y$-K33nsivq3z1P;PPNMN(&V9Ho$YX=?WTjh4qh*vGLR&y zTAPT*>&I*#dfkfEbe5Y*Bvtv^t(<8cOxZH|r3FWa-F1# z>o6Q^OKvy!9(p(DUL!FENl4>Lo<(?A*rfO}`tnnku?J|W?5^#6bOs%1_8Hv0-#*uP zM~P+gLhk~fdRl0)#w!)~LP%Qj8M}8+Mo4t@TB`)gdl1>jw`N0A=d&GtieXBmguUt! zXcKx_3w1y@;}5X?#ekHAj=7>z#e~IdVvtyRic&Ck3gzLsmXj| z>r^s#Ikgh;!?&-pkR2^OzG2kTFk7=4vEzlEVpclfD7t|z228JJP zMp`w)lxEa~jzAHS;R54%R@qmxnqk{#F2^|f)hW z*ZMoKGpKBr1w^PC$T5n)+iyBC0UNv@?ctQs#;HnEd7=z-HXd%$sKzqXq)-FdI+tuC z?ep)fl>y)hmZH|RVkVX`kPteLTy4H_3U_UO|M7-CXG)oJ!<{T6-ou%9$O?%^eCJ&W z2mV;Ft+3dw&R&VE8mQCA%NF7l@xbuPB0Ed`wa-y66R+97!orXiSY!{m z=N@hL@}s^6g$!jYS2Ye6|a*nj$06C&IS- z_+z0pcNW9>t%4js@Tn2J{svNMmxpeH42BHkaS)IWZPNu!sUH)!+V~n?4|r>N4M~aK zbmPwt+#+TpMY|Wmo!MFhx%5`yyV~{PH8(65ddci|Pw?8xdd8iZL2I;}>cF2v7Ir#u zGZGev?v9_|pFpA)@SWo^?(pvqO{1AMK{z{}AREh?eR zez@$A1=I}tw$&!}_#$nRE`pMgTKh78UFC8B@6yn~m1qIPcdds7xrS+XmWVqGE2n6Z zGjAL~y8GTE7fOqg&qoV?+nd1V8oA87mwl*~RRI!Z&YIOV1mnRI!^rPtBWPUqF7ID< zaeMSKb;0YWYIU6w5RT||?)19ttRJ5D$mj>#+oTD??dC`9T9iB4_UZTmBp2RYOUSFk zThcK6qQ4*vySX(Jv3SWVn7a=$b`Z+^S*L}lx?sMh84b$+!;A#Pg9YRzc^bdOc-zS# z3szI1G3Z<3~AA*_eq4v`reC}l(^MKM4 z@67GIARLBkIBhA-R{-P35(F(t=E^H*MfH!;g)o5w*?~v=tNAWdq6PE?)E%uHgw#*t z)uCI3hRJ@N6M9881vUtwy+u-E4%Lm-zWxIv?T}up&~)l%u20b3Pv{`RyE~m;lLKSg zN~K6EYYJcA`lr}hzH>Pff2a)h;_wpFil3ZAabT&?zjAkZw3AEN1CQ?d3w^IppIF#| zVnFi9cBTA>p7*az3Ew%y=jnR8JdLL9fHbPV=U1}UmWvOK6Rx1XH>B#Ec2E;o^;}ku zaKY(9Io1m!QQZ5ucP288ej3(<@w2;n>ielg%|Q7zgj4eDA;eM^Q3k@pz-`oK(z3%3 z6>ENL7lkY;_V!grbJfPO*k5>WTJP=ni}tk`wml`QAE}`9b8a-~@Nxf4$<25yN>4@d zc187Qdsc|wQvPQixT>JQ{dnzaa!Qy(@U8pP;YBcC*%knk4$*moX=WE^w96KtLVf*4 z8z&eil5`=fQg;R;kwX1gZ$Tb&dUh)E&|PN!8b17*8ZF`mO=KopYW;ZW0(LJW43fz` z2&WmF`4mS7i}Bb&y?8sl2Cn)UsKsL;Y{IDR9mf_#DhV6-igh@%8J-dEKkS1##~kw% zQ;KpKE4iwcO!3mN*&&Dlz|`Zvjnj6Gm|lK(NB0^HuDrK24)!2v^){-+_qJL^2=~UA zMZI3}P))CLN@87b;_#ilcIAIwndY%0JP7Fp#O<=ZL6QqWb16ofTmT46l6dq-LqS2u z@a(}w8KC;rcKt7{_OarLy&$QlR*Qy^_rgD8mINSO&^MWUgQsIytJ3qAFKn< z5}Pe|J{swdZPn0g=e~=k{fzPM%>X*>UI2&;R#BRgMYQ5^QgHv@prKj$?|?X;GY$(M zL}W(;{SSW*(1hm>MFzKAQ-J)Xgre1_MMn(HPYiH_GV*0O-hfaCm%0yB|Ybk|JFn#W8I!&F2Qf58f$KfO8^XW zJzuZzm4M|MH#~qQa8K5-r%8Qz0S#Ka&zHPTvDC6XpvT6^q7^D;Y2ZrwI@q7q5+S(Q z535|!Tx_4%5o_N#wtZghb3$90jgY(dS@u{@FMebj^2A;LIvw8cn{tpMa?c`08-0$P zU!*IzPTEhK)Nl^BbDpCNA)JA$eTdHe+Bhk=aol^ZlG+X0?WXyvLT_j+mxa*HwRAi5 zv2E_^7GTM;9_+5Z%_T;7IXoD55pf7_(aOw-P}g%` z*-qQ9wtQkZPC6=*@mhNTSBjS=_A+QBo-!B%xBM>kCjC~UytI|@rc|9?=3BuIWr033 zwXqdVs=w_ZJ`KOqqJcPG_x6Y5r?yb>%v?E@$cr?SOCRsfkN+jO#ZUhb0xk|%<#|lT zYqGn^Qwt&ct=XnLZ>1&C!B2eErrV1N@?9VQ?r>6p3fNDO4<w||Uovq`EKJ?hvbl4&LkFyBs73Nc3jLF)#^6Pt4RfSR&W zoFHn_{Uu0o+BiQ=wCZ&)1)tQHl+T~yNCx`Qnnl9%I&RqiYtLn^mRmYGV`cK`nmTmks#Y;O*Zjbuw*6asr?Q{(;g2 zNs6!SPq{4#_4`Ph89B2;Kwe1>1?P3Y0^KNdTD1-32sS8M=S zOnJF_X&Syhz}|ScF3=OGcX!l@@UHy{z*%{Dd8Hj4CV@&@W(?qy%28rI5w9IhOh4Z+ z19HCIP}N`O>A$>6-y*niTjqDO*}a=rEGX*52HbQHwnOT{rqu+%O|7EOK(|A!!?$oF z^Z_edlWULCp8(*bz)TF#-}+|f8bLcye`&rm-a5TZ z%z+8{8Ln_+&(;aKOAWx(|3?l*&p{ES;XmfXyYs{y5PmTWF3G8t?TOlKSW9Q1gfU24 z_Ult&9zY{r&&+gD5#L5Cm^2H1n?blk(nvNXj)jSyjB(m(l2n6CRZoz?9vp%j?g;d- zw0(B>YYdVc-&Qj@=}ru{QtSXg1(vTpP=t4$E9EPbmlz-Tu+MmGfQ$wR`R;F4W z%2Ya3c)XieGS%Lat_C*Sf*TQFJSyZ$8|II@t|nlh*<=gQ|HSg*d{l!PpuAA7!(APy z20CU`(x!myNHtK-lM~bsJb!h4FyDH934h*igR#!$XZ&*2>E2CFs%fb)ZW}t`?BYufF{9*gNb5puAHB zG_Pm@%7FAYQu5tQ?ot$xc56#gb#}D?)a2HwVDd)0IlswvbPaIFGLJ#B=S~B@!t%F! z2e(e!!3}6r&WI1MB*&}(jbukr0^82L$A8fZrl$Cf7_aL*q7kqdX`myg#=RexHrgLv z9R~>IHKfOi8MikSxPhY~(Bi}wAfjpjO+OQ^EE0vr2(@=H)f-vz?Yj=$>eXT1m?Q1m zbrj^qb1K_9hg>&e&!c=Upp8`uAYHj~1CbPfSb<9*+{v@d6%- zq5ms?#cUo+4*fe5K)D%TOw~pKC43h^-68K4Lw4FCaSQnsSpJW9Y{XNeF`Z0iKAZP9 z4=|uFAjFe*0%&Mjtb^*^KI^RMv3>0l9xvJqJ2GPmVC~`A$VO-|Y zj&>O;SB~JtPJ4Sutzm_V9BWQSK&t=YmJUV*+eK0w`A*4&OD+xd;l=CPbhzNRWRVX8 z=4UxeE9^W3kQp3M4|AcBbl;JsFvrJ(I0F@)7EecN27IF2H6qsnNZ!~cpQ(aG4fhTS z05H1*Kst*+%5S6fz=!6IzObxRKw5+qrbi2z>3j1NEfk8`Xh-{55SmP@_%#>1;U+9) z1<)tpNi3u8OSHEm5f#HhPc=zJ#m>p>-`MH3zl*&EGEc(2GC2>FVSlqp$@A%Ee}mF<6E(Ophpxjq;>W^QsqTkGW&Fvnyp`gNLFJm%S9|yd zz$OM#A>YQ3)@TsCU)@zxK`$r8(npN9(3vt5Hds@Zc3)jDN4dh?Deg6KL+}2EqjH-xwP#HRoiD|7GN+0DQ+z~1_wHWbw~ zuNn|Y5sP@Bm_`DLd?u22*vRl(ssn_zL2HuM4lV}*paal3yV#c$JUcNrsyM$jeCjoy zo1oogdN|hK&$p@c$Bs0(HBHWIco!0eymv==9zB1!Y}ga*GnNo>vIVnq(Yb=+N_MF> z|GxA-S2W9Suydik8Vmni{nV{az7F5kF?a7g$-<{yi?srWK~7{jA3nk|A++B{L%Ab8{(eiUmeo#2&_QL@cYPu#wLPP(Pf4DX{S6^d zy98q=wN8drEv6XIK{P!Q$3UpE(BW3?%xq_0TVg$tg_HJmB@u82X)~nGEWhtnYo}ol zl0nmaqOl{)IBm2e>%3!cr|aWDNmB1voGeopLNV5cNom{K?}vL}b4$%vCE=bF542>G zF*k2tdp7@lP&LBGIGu{~kANY%l4l4tafxAdYW;R)T6b0LDj4`!x+^|FTE`%a%C0Z% zV!C}EGfimIBAu*`t9n{KqcR83CFf@}hwrM68rNa7u}X3EZH!6#)tA19+q2TKafw4y zq1Bj?_@LEk002~XN4Et7rp2ACzD4n*`2$@HWczbQaIz}F#r?8e?>17h|){eBG@wil>33ZQYZ3Pg)x~ zLN=D34UA4&MKw;hf?#d0$a;dS2&!m@bY>$4A5ZopziT-{tFz66$u&)C(4VHO6jED9 z{|KmQX7l5c^trWO>>xHQfzz1iM0 Date: Tue, 4 Aug 2020 16:12:52 +0300 Subject: [PATCH 11/20] chore: update yarn.lock --- npm/ng-packs/yarn.lock | 564 ++++++++++++++++++++--------------------- 1 file changed, 281 insertions(+), 283 deletions(-) diff --git a/npm/ng-packs/yarn.lock b/npm/ng-packs/yarn.lock index 0f72400c00..5f274d1935 100644 --- a/npm/ng-packs/yarn.lock +++ b/npm/ng-packs/yarn.lock @@ -2,20 +2,20 @@ # yarn lockfile v1 -"@abp/ng.account@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-3.0.4.tgz#5c75a30c912294b40cbc43f218d61cbe67a58355" - integrity sha512-a+ZjFoaNlJAYW3Hd+hEhq/TCVENc3x9D4Grf5/zr8h1WcETdgjx8rvRxhj6l6i/Ry/mAgPHOKuObSbb+pxVo6w== +"@abp/ng.account@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.account/-/ng.account-3.0.5.tgz#3f359e07be021c5743f42f32abc8371f93552df1" + integrity sha512-isG8VmENHookDJoq73dJfPbAdLxmzPGAJMDvg5Yn124yfHVkZQONszLGZxDNUFWti0S07Xose5dripNzcK2Clg== dependencies: - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.core@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-3.0.4.tgz#ef86082c13d1ccbf0c48fb2b0ccd5a059e44215b" - integrity sha512-dBHCtcM4dVOvHJ88p8d71qpYpOvTjrvu78e6LO6qK7CsSoJq5B8EkYZgkV6MO2Kq5/p3mLHTtwuP3mkQSUfLJw== +"@abp/ng.core@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.core/-/ng.core-3.0.5.tgz#8956c4e27689e80d981bae66e173524c79ca8678" + integrity sha512-PTluEXyea1d5oPtvkNx/SbmX3kBaHtdiJyN88vJoZXbdd5/OIZeeR5cL4Q58+kYG5xf1z6xkq7wNSAzRjTG7VA== dependencies: - "@abp/utils" "^3.0.3" + "@abp/utils" "^3.0.4" "@angular/localize" "~9.1.11" "@ngxs/router-plugin" "^3.6.2" "@ngxs/storage-plugin" "^3.6.2" @@ -27,81 +27,74 @@ ts-toolbelt "^6.9.9" tslib "^2.0.0" -"@abp/ng.feature-management@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-3.0.4.tgz#127a81c9f8b045c38bc41de4ab49d29acaa14f70" - integrity sha512-TVNmjLhhg0VbaUlaXeDUsgpz5BX26aMzAY0dahsXhyM/dti2slIlEyyTKf673a1ve84nUuigrDJiAhi6WntUbw== +"@abp/ng.feature-management@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.feature-management/-/ng.feature-management-3.0.5.tgz#d947f9f05e9edd7c972c42ea903bf05d89efe8da" + integrity sha512-TUrKF5U2hjQ92/Ocig7uULNCew++dfIpCyoHdXrcWZHdhLiFcuuNLc0UElPjFe7WrIuPkka/28MEWHylKFAk4Q== dependencies: - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.identity@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-3.0.4.tgz#321ab33db22d32013d2ea635616f6402717ebc40" - integrity sha512-ZJVh77gZVPKyexfLxo613NeiKWYSk/7q6QrMEzkeDM21R9VLyw5jGg00pw7hkmUldy5bObW/5VVCxJlCzSTwdg== +"@abp/ng.identity@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.identity/-/ng.identity-3.0.5.tgz#474119e9d3ce2529f0b03a3241d41ed1d49faa65" + integrity sha512-v6hxUniSyIknOidXYuYFvV2edNksDIBgiB7LvqY/csmddH+fHJhct0W0bdk//83aj5N/Fy3FO5BvkeiGYSFMRg== dependencies: - "@abp/ng.permission-management" "~3.0.4" - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.permission-management" "~3.0.5" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.permission-management@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-3.0.4.tgz#511226c1c0e1445a453015d8d85b013e7a009f96" - integrity sha512-hIiUdQh9XVvfmLc5B+eQpj36PxCcBzOCRRaBuGhd2+lecEVUV12EgpWq0fzW1laL9FV1REmqIKP5uzKUeUw4Dw== +"@abp/ng.permission-management@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.permission-management/-/ng.permission-management-3.0.5.tgz#2d496872be5af52e8f50022a5c36b3db989c9bc4" + integrity sha512-ukXX/v/ECU0R4SNKNwwdLG1+bbbS8r2GabaefX8IHYxq084VWXWlM7gTgStDIsvgC3Trh8Itoi7uVJHCU6bb0Q== dependencies: - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.setting-management@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-3.0.4.tgz#880a8999e6f77a46bebb5c3ec2e53e652cb6b289" - integrity sha512-mnjxofTqE+n9C6x5nZkb0DQK/s0cZLwCFrhFoJdiQmfIewHU4AVbs7cT6L7FNewYwojPsCsppiR+y0cUaXDlMQ== +"@abp/ng.setting-management@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.setting-management/-/ng.setting-management-3.0.5.tgz#57cc71d3357b73fe4f8890c077916c616301ee97" + integrity sha512-Cd6hTXS9XfIVmzwStICijEzaELDn4++xVUmVncWLJn9dWW5T9Mau+kkn7SeElzmv6U/iSEZH8/UHshktCvJ3Tg== dependencies: - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.tenant-management@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-3.0.4.tgz#3e4edcb94b11b190451ef08115409f59cf164088" - integrity sha512-3lcq80Isa+gTZOKOyzQBd/6t4pe+mOakjZFWOBOpi4gmy4Mmun1KqbfaFoMW+v0wacQPGiznStdln0AeOXXj7g== +"@abp/ng.tenant-management@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.tenant-management/-/ng.tenant-management-3.0.5.tgz#ade0e26b26dcea5445842a21f5a1f675705dfa50" + integrity sha512-2etqlpCB2iXCXSTX1D/YSl5WIXgTvPMFUaOQ8r1CFVxdOhsmWgS/8JZEEZMO5oJDKMyw/jibqtY9WeqgdsnJQg== dependencies: - "@abp/ng.feature-management" "~3.0.4" - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.feature-management" "~3.0.5" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.theme.basic@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-3.0.4.tgz#655e4388f6dd91eea10bdf14f313d92bbec3cf49" - integrity sha512-bSIYntH0gF/HJVYOvuguZfKkkmA6zALSVj6OYQPNo3HW7+N++loawnbMyEbiBSd0V8JolkFHeX/xvOGlY12jnw== +"@abp/ng.theme.basic@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.theme.basic/-/ng.theme.basic-3.0.5.tgz#13d3da2547fde92a66eb5fc9f9798892226e63b2" + integrity sha512-COeCirRKpLcY2OE4cs9CrKObA1XRRaHXbRcKnMovPUcxC4xb47tQ5snZ4n4C9VYkRnlpSh8p2w51a8SQuxQjMg== dependencies: - "@abp/ng.theme.shared" "~3.0.4" + "@abp/ng.theme.shared" "~3.0.5" tslib "^2.0.0" -"@abp/ng.theme.shared@~3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-3.0.4.tgz#d12f560b7e90d91a659c1227bd4e8c25b4f8cd3e" - integrity sha512-0Z37zIiNU0ZVK7F5nP/7uS6ppPGlltUUvlf/l6RdOKi4aUbUtSRqDVoAbTl29AV14A8gicWkSFYKK+2wxoN09Q== +"@abp/ng.theme.shared@~3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/ng.theme.shared/-/ng.theme.shared-3.0.5.tgz#7d0187621d5e27bcc171d21d8ab0e5f7241edef4" + integrity sha512-LAokCastVsEIMH+HfQjkkt6OotKNrIFMCMlDs7Y7i74sXGGhhe+v4hHsWlAT4yQ0EydNYr1W10XoI7B3pzH1MQ== dependencies: - "@abp/ng.core" "~3.0.4" + "@abp/ng.core" "~3.0.5" "@fortawesome/fontawesome-free" "^5.13.1" "@ng-bootstrap/ng-bootstrap" "^6.1.0" - "@ngx-validate/core" "^0.0.9" + "@ngx-validate/core" "^0.0.10" "@swimlane/ngx-datatable" "^17.0.0" bootstrap "^4.5.0" chart.js "^2.9.3" tslib "^2.0.0" -"@abp/utils@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-3.0.3.tgz#563aa062882ca82227b749d90458adafa46ae73b" - integrity sha512-eV4cl605j1IbuIbnTTO5JW+O3mpUUVxp+AG2xqIeqrRSnyTGhTG0q30XjsDGlTdcUfwxpZORptD4pu8NfCGUpg== - dependencies: - just-compare "^1.3.0" - -"@abp/utils@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-3.0.4.tgz#38068fa8f735e1889cf2f226128366825948814d" - integrity sha512-TnXRZIZcxv5+EctEPsZEi2cyRXbpl3A679wzQa6BACv+pM45cjGO1JR8P0VswKN4TVL0aQRMv26N6U/uie8sEQ== +"@abp/utils@^3.0.4", "@abp/utils@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@abp/utils/-/utils-3.0.5.tgz#66b3da953500e73ff1f23d1b41168cde8216ce49" + integrity sha512-X9V1xLIEazItaf93nFSA4p94WT6QK3yA4eIyvU7GyyEkkOQdaakNwPbRwy930sd+I+/oXnIqM1vDsJu9QDhgvg== dependencies: just-compare "^1.3.0" @@ -115,12 +108,12 @@ jest-preset-angular "^8.1.2" lodash "^4.17.10" -"@angular-devkit/architect@0.1000.4": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1000.4.tgz#2effe58361bea2a77d11671743568ab4d50b1554" - integrity sha512-n0DXdrecxXupxKf37sv5Oky5QpQXOHPgLDAmyAwevr31yLEwyZ3OQoVxaC68AMQJFYMlHYYMwi6gdIcFmL6W0g== +"@angular-devkit/architect@0.1000.5": + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1000.5.tgz#39488b92a366e49d50dda0af4eee3b0bb9425ec4" + integrity sha512-BhNqB7fmmrDQwxoJ3zdw5FslFD+nYGgMTiC48ERVYJVuN3BK6xtt2OGA7vho3eJ13OE5cPGUi8crQDRROgxxQg== dependencies: - "@angular-devkit/core" "10.0.4" + "@angular-devkit/core" "10.0.5" rxjs "6.5.5" "@angular-devkit/architect@>=0.900.0 < 0.1000.0": @@ -132,14 +125,14 @@ rxjs "6.5.4" "@angular-devkit/build-angular@~0.1000.0": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1000.4.tgz#447ebfc16afaa7638099e2f183144ebdc0e2a1a4" - integrity sha512-jAl2xsj1g4RdQ4MBLSZ8Dsj3MUKjYKK+e73DxVHSTo0166T1p/7gdgSehLHWVlavJLDVM+fjYdt4kP12Z7FBjQ== - dependencies: - "@angular-devkit/architect" "0.1000.4" - "@angular-devkit/build-optimizer" "0.1000.4" - "@angular-devkit/build-webpack" "0.1000.4" - "@angular-devkit/core" "10.0.4" + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.1000.5.tgz#9be7c63d96d3adf7d6929a09618df9c57d61f76e" + integrity sha512-YOlYdOksFsirCV7l2S0T/k9phRtT5eR+Pk3uWHXGfrkCBzFlAHw1EqOlJLOOSuN+stGHHYnKES2WUVJRJXLlCQ== + dependencies: + "@angular-devkit/architect" "0.1000.5" + "@angular-devkit/build-optimizer" "0.1000.5" + "@angular-devkit/build-webpack" "0.1000.5" + "@angular-devkit/core" "10.0.5" "@babel/core" "7.9.6" "@babel/generator" "7.9.6" "@babel/plugin-transform-runtime" "7.9.6" @@ -147,7 +140,7 @@ "@babel/runtime" "7.9.6" "@babel/template" "7.8.6" "@jsdevtools/coverage-istanbul-loader" "3.0.3" - "@ngtools/webpack" "10.0.4" + "@ngtools/webpack" "10.0.5" ajv "6.12.3" autoprefixer "9.8.0" babel-loader "8.1.0" @@ -203,36 +196,36 @@ worker-plugin "4.0.3" "@angular-devkit/build-ng-packagr@~0.1000.0": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.1000.4.tgz#a449169210b994491cf6048d07b246daf74eb1c7" - integrity sha512-YcqXv0+mNEAUtFI2XtoabXNxlTfgIsFobeoGwdfe1tVn4b465FIgqFDiNFEgaZ4UZbdbLuk0yrVHpk/f8X/wzw== + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.1000.5.tgz#681774fa8982bf092e7ee33a19842e531a36a4dc" + integrity sha512-MiYwlyz6LOQONEBZMiaN3U7/CpsttNKmphdMmsBZyIPBnlHIHeHgekUEjYSMJDI9C/31HsstVR2DIJjOD2nJmw== dependencies: - "@angular-devkit/architect" "0.1000.4" + "@angular-devkit/architect" "0.1000.5" rxjs "6.5.5" -"@angular-devkit/build-optimizer@0.1000.4": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.4.tgz#bdeb610b042533dbbc3c14c52f81f2f67bfb6513" - integrity sha512-usscQipxIU2yJVmBdyIDPmJZ+ltOjsX4VbMkGM2IdJHCIi9uEk2E3+YLxzyU5Xl5tXEK61AQt4YWUimt8Kg0GA== +"@angular-devkit/build-optimizer@0.1000.5": + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.1000.5.tgz#dc1e6fa38b7ede190ab1f31867011e624fde83ed" + integrity sha512-H6jTF7TOYq909HR6M3Bu8lScqrG1qznK2XMefK3m1I1jBJ+WO4bL7hrhTp/CIY3d+47txep+XqhitDWD/6ikpg== dependencies: loader-utils "2.0.0" source-map "0.7.3" tslib "2.0.0" webpack-sources "1.4.3" -"@angular-devkit/build-webpack@0.1000.4": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1000.4.tgz#781e7d67dbc80932e933010fea96339e10a7eec8" - integrity sha512-ZPXrm1+UyKbMZtnU+b5jdtZPFDYs8Pu5lHhJDzX6bk0TxtuXws+nwaeUs6WkfwXft8cksxK2WwGr57XX3OT7nw== +"@angular-devkit/build-webpack@0.1000.5": + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.1000.5.tgz#040f58661cb81e545d2e2872ebb0b55ab695e27d" + integrity sha512-233EbW+6IKJEV20IG9Qzlz8MdDedzoTheB+lx9tTPn21m0ph2vmpTsNOsmMWwvdBBgXbv3pW3SMbJiqDCh7u4w== dependencies: - "@angular-devkit/architect" "0.1000.4" - "@angular-devkit/core" "10.0.4" + "@angular-devkit/architect" "0.1000.5" + "@angular-devkit/core" "10.0.5" rxjs "6.5.5" -"@angular-devkit/core@10.0.4": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-10.0.4.tgz#105df3e7a7df56005f3637121ef010dd3849f5eb" - integrity sha512-Pe60BJCcAVtOkhXn2c+ql1NfyMCu421jWmKwl1KsW1DXclpGB+UIa560ICBgEwla6DyltMKEN/lX+P4WOskpkQ== +"@angular-devkit/core@10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-10.0.5.tgz#ad747edbf3344a87f86acb71bdeaac0380538c04" + integrity sha512-ZaF1EYniIo+yRLvvaKnLrjYCdKeg2U3YtbA932M2AIfjgfFv/9mnAbH4jmZsBZhCstxZPz+ItwJesdR20h4Z1Q== dependencies: ajv "6.12.3" fast-json-stable-stringify "2.1.0" @@ -262,12 +255,12 @@ rxjs "6.5.4" source-map "0.7.3" -"@angular-devkit/schematics@10.0.4": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-10.0.4.tgz#73e0021b01e4c35d3bf54111824793527c5ec6e5" - integrity sha512-k9b73XkKQK8yFbq+dQqJnxAMG3mm/YR1KQlsQzOEVdw8cqqEALLoUXg/73hT5eUnSsNWmyDLBzEAyNtemmmI4w== +"@angular-devkit/schematics@10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-10.0.5.tgz#a9365e06a433c89f0cf7e0a0937ab17816206b1e" + integrity sha512-UeeV8O0IydxCKj2oejygs80oIAQXPYrJHo0PQ/fa0RH6rtV3wZwirdy+yqq/BDGhtV/5VQSVCvu6uyAtGGMgNg== dependencies: - "@angular-devkit/core" "10.0.4" + "@angular-devkit/core" "10.0.5" ora "4.0.4" rxjs "6.5.5" @@ -280,9 +273,9 @@ rxjs "6.4.0" "@angular/animations@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-10.0.6.tgz#ab1d7dd5c7a76da2528a705f5186733763eee545" - integrity sha512-D2cDrfwnVjL0/6m1v35mAYebH2z0I3WJXohhePaDHEKBEXfXpBIbqqSiRpV9jLSa/xgmJPh4FSNVDCmKmuEmfg== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-10.0.7.tgz#1896b76bee50abb5a199b335d447f9fcb195ab1b" + integrity sha512-lTF7wuhx16fc3WahmqcYE3Q6sHB5sUQZ6m4dKg38wuf49Hr9x8uQpOMypnOAp9qfKG06ZZ2arRs53JeHpzkMPw== dependencies: tslib "^2.0.0" @@ -294,15 +287,15 @@ parse5 "^5.0.0" "@angular/cli@~10.0.0": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-10.0.4.tgz#5c13500f3135e43b9e6e53534fdfbc283abb83cc" - integrity sha512-hmr1fXT8+6wOoh7abIg154wdP9QCMPHMShWPEYHks6ARmlRfX5k+BykQMzgI8H6tMNLoR+DAlO5+pPouJEyilQ== - dependencies: - "@angular-devkit/architect" "0.1000.4" - "@angular-devkit/core" "10.0.4" - "@angular-devkit/schematics" "10.0.4" - "@schematics/angular" "10.0.4" - "@schematics/update" "0.1000.4" + version "10.0.5" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-10.0.5.tgz#04628246ee6e5428c124ea14656fb1b40f819408" + integrity sha512-Qsa90IGPApJS9HL6Ih7Z8S8mIdriWYEintsT9cfI0WMVYyjvSNZQBf1SvnNU3IEboV4RFnpfXJNmQz1Q4KsRFQ== + dependencies: + "@angular-devkit/architect" "0.1000.5" + "@angular-devkit/core" "10.0.5" + "@angular-devkit/schematics" "10.0.5" + "@schematics/angular" "10.0.5" + "@schematics/update" "0.1000.5" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" debug "4.1.1" @@ -320,9 +313,9 @@ uuid "8.1.0" "@angular/common@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-10.0.6.tgz#c279d771eef1e623bd8336c70c3ee821bbebbdd4" - integrity sha512-xS9IJGg6s+Y3K7pe9Oz39Dnpq5uSuUj3HkLKt1db5vPPAeT1qdZ+rdH5hnGwbf8Ihd6ZQacTAlh9W6MnqorZ0w== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-10.0.7.tgz#16dc489ea2e53563fb972581e3b3de46ebd194b1" + integrity sha512-CPjmbjylbMG0eFLWz7TCaxONDcwuldcvEheEwaBGS3RloHVsa+ry/8r6/7YilQkscdNPUazhX8pIzzrxIf9cBQ== dependencies: tslib "^2.0.0" @@ -353,28 +346,28 @@ tslib "^2.0.0" "@angular/core@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-10.0.6.tgz#91feaa070a65db22cf8eb65523351b653ce80d2a" - integrity sha512-mk/7XmZg7EeWEgl2UEyhyU6eukm2h+Thw1Ue84aBxMDaqt1RUpsPwpGCfIRfzH9gdzAjJUAPxiHAN2CF+3Wohw== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-10.0.7.tgz#297392ea4cf0764de28ac8efc7b4f041db507efc" + integrity sha512-h8R/2TCIFkagrFl6zmPN34gS5ZtQ1soYDI8dDeLj0+oQ+qH8HncoRgzYl+1+agFvUeYQ2pkwc5i635j/LwC++Q== dependencies: tslib "^2.0.0" "@angular/forms@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-10.0.6.tgz#5c98f7ef95f716986968a51946a7b1b9e6e36d40" - integrity sha512-C/+o4lLqyE2QX1brNBxf5yqBPxNpfRA8Rv0Nb1nQE0T6Y/AjyQWxYYl34fD6zk1WQfP3X8bUgkbhHhefmjVZKw== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-10.0.7.tgz#571cbdc5ed213e10aedfdb9d660f4d55c71687a2" + integrity sha512-xSGPhidaUWLop3j9zPy4ZeO+/rwnusNWvwrDNey4W68lS068AExRXqf3yTuzobqBGdV2swDJaRabzgD7NS8yag== dependencies: tslib "^2.0.0" "@angular/language-service@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-10.0.6.tgz#d76e8f1850e521f716c15755b869ea4e49b8c59d" - integrity sha512-Aaee3kjmIPnTQJZL1+eBgkP+bnNh9zj6F78WEoYX7lHt98uRBfv3C9Wl+S4Gewoe99d7BZ53JdthsKY+ejCSIA== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-10.0.7.tgz#22a10d4ee4458b946aae376cf8d502c78b956a20" + integrity sha512-iD1It0GjQyn+1KKVh0IMTtrRw/HI0cXq69KYju2LXckngzSK0GXg+yvPP4sizwSBhJW2xeepV8qGkpGo9M+Wyw== "@angular/localize@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-10.0.6.tgz#da109c374da8576fe48ab13d3487bf33be65c03f" - integrity sha512-wcdPphTnBisN6kE37lilt4U7yJKKoM8NKz7hpSq8KTBvf0LN4AfYDzkIJbuapKeolQavblIKgAwkXzsjBhBa2A== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/localize/-/localize-10.0.7.tgz#ea99439ad94420cad73b23930f6d091c2e470c13" + integrity sha512-20PciUxCyVdIAkvopzGhmU5LA0bFRXmPFpfDqBccUn9tFv27PAOjNf70HbscdUKzEQW79kLjdV5qcbzXZqPnCg== dependencies: "@babel/core" "7.8.3" glob "7.1.2" @@ -390,23 +383,23 @@ yargs "15.3.0" "@angular/platform-browser-dynamic@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.6.tgz#664424e27a38dc599bf6003284ca3938f1450b32" - integrity sha512-ao6i9mEy314SI9Z57JPyKvb4sF61i2RNKHN/XuTpPBIRJ8ryOhG6aS1kN2gNFfj8HmyxZS0zohxTxd+nGitGgw== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.0.7.tgz#e419f25da20bdee5ac7c7c3b1907f4301cd7a363" + integrity sha512-ESn1hssKmgFbSSU8tI3KcP6QFEMKaxTvoKElkwULhAnCNkeXAhZaIkTdeqaa/vkO8s9nRbRwqcLuhw/mIQJbpQ== dependencies: tslib "^2.0.0" "@angular/platform-browser@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-10.0.6.tgz#1a48add3a697105ea5f1bc1e72bb6336c4832dbf" - integrity sha512-i3jqfXK6ZNwCJbCadeUC+ZAGvXZ0/k7/LocxKACFQW4a5o1W8aACn8COYDvdKMsT1B+tM9Wv1nDh3qjPZthaXw== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-10.0.7.tgz#c2328f2f5dad78da79c35fc8eb2bb6bacad81171" + integrity sha512-iACZDApTWTID+Dgpv9ztAlmP4OBIyCnqfmSrVWIpN30O/2pgalYS4hKS+jFXXjqG3IXrG6IpOAbFT9UubOWXKg== dependencies: tslib "^2.0.0" "@angular/router@~10.0.0": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-10.0.6.tgz#c1e7a6b6a5472baa345fea8f472e9e9a7ef20c3c" - integrity sha512-+5c/1KitUeMHd7FPAKJ25aloouFHEjlPe5KKGJFtkuzZ7SOi3zwF3ASR52ysnGs/YymdBakIY8kg1Do00xn2wA== + version "10.0.7" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-10.0.7.tgz#8fe294f1054214a8aff9a3d982756a4b4dcf6284" + integrity sha512-uZAUTSQNuDvpkWGqF2qTkqr+btrNwg9USRB08lzhkWH351Myt1S/7ECVYOWNek6b/NmlAA+e3Kcyb94uDwMEew== dependencies: tslib "^2.0.0" @@ -432,9 +425,9 @@ "@babel/highlight" "^7.10.4" "@babel/compat-data@^7.10.4", "@babel/compat-data@^7.9.6": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.10.5.tgz#d38425e67ea96b1480a3f50404d1bf85676301a6" - integrity sha512-mPVoWNzIpYJHbWje0if7Ck36bpbtTvIxOi9+6WSK9wjGEXearAqlwBoTQvVjsAY2VIwgcs8V940geY3okzRCEw== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" + integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== dependencies: browserslist "^4.12.0" invariant "^2.2.4" @@ -484,18 +477,18 @@ source-map "^0.5.0" "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.5.tgz#1f15e2cca8ad9a1d78a38ddba612f5e7cdbbd330" - integrity sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.0.tgz#73b9c33f1658506887f767c26dae07798b30df76" + integrity sha512-mkLq8nwaXmDtFmRkQ8ED/eA2CnVw4zr7dCztKalZXBvdK5EeNUAesrrwUqjQEzFgomJssayzB0aqlOsP1vGLqg== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.10.5" - "@babel/helper-module-transforms" "^7.10.5" + "@babel/generator" "^7.11.0" + "@babel/helper-module-transforms" "^7.11.0" "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.10.5" + "@babel/parser" "^7.11.0" "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.5" - "@babel/types" "^7.10.5" + "@babel/traverse" "^7.11.0" + "@babel/types" "^7.11.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" @@ -515,12 +508,12 @@ lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.10.5", "@babel/generator@^7.8.3", "@babel/generator@^7.9.6": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.5.tgz#1b903554bc8c583ee8d25f1e8969732e6b829a69" - integrity sha512-3vXxr3FEW7E7lJZiWQ3bM4+v/Vyr9C+hpolQ8BGFr9Y8Ri2tFLWTixmwKBafDujO1WVah4fhZBeU1bieKdghig== +"@babel/generator@^7.11.0", "@babel/generator@^7.8.3", "@babel/generator@^7.9.6": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" + integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== dependencies: - "@babel/types" "^7.10.5" + "@babel/types" "^7.11.0" jsesc "^2.5.1" source-map "^0.5.0" @@ -600,11 +593,11 @@ "@babel/types" "^7.10.4" "@babel/helper-member-expression-to-functions@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.5.tgz#172f56e7a63e78112f3a04055f24365af702e7ee" - integrity sha512-HiqJpYD5+WopCXIAbQDG0zye5XYVvcO9w/DHp5GsaGkRUaamLj2bEtu6i8rnGGprAhHM3qidCMgp71HF4endhA== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" + integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== dependencies: - "@babel/types" "^7.10.5" + "@babel/types" "^7.11.0" "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.8.3": version "7.10.4" @@ -613,17 +606,17 @@ dependencies: "@babel/types" "^7.10.4" -"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.9.0": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.5.tgz#120c271c0b3353673fcdfd8c053db3c544a260d6" - integrity sha512-4P+CWMJ6/j1W915ITJaUkadLObmCRRSC234uctJfn/vHrsLNxsR8dwlcXv9ZhJWzl77awf+mWXSZEKt5t0OnlA== +"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0", "@babel/helper-module-transforms@^7.9.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" + integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== dependencies: "@babel/helper-module-imports" "^7.10.4" "@babel/helper-replace-supers" "^7.10.4" "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" "@babel/template" "^7.10.4" - "@babel/types" "^7.10.5" + "@babel/types" "^7.11.0" lodash "^4.17.19" "@babel/helper-optimise-call-expression@^7.10.4": @@ -674,12 +667,19 @@ "@babel/template" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-split-export-declaration@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1" - integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg== +"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" + integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== dependencies: - "@babel/types" "^7.10.4" + "@babel/types" "^7.11.0" + +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" "@babel/helper-validator-identifier@^7.10.4": version "7.10.4" @@ -714,10 +714,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.10.5", "@babel/parser@^7.8.3", "@babel/parser@^7.8.6", "@babel/parser@^7.9.6": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.5.tgz#e7c6bf5a7deff957cec9f04b551e2762909d826b" - integrity sha512-wfryxy4bE1UivvQKSQDU4/X6dr+i8bctjUjj8Zyt3DQy7NtPizJXT8M52nqpNKL+nq2PW8lxk4ZqLj0fD4B4hQ== +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.8.3", "@babel/parser@^7.8.6", "@babel/parser@^7.9.6": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.0.tgz#a9d7e11aead25d3b422d17b2c6502c8dddef6a5d" + integrity sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw== "@babel/plugin-proposal-async-generator-functions@^7.8.3": version "7.10.5" @@ -761,9 +761,9 @@ "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-proposal-object-rest-spread@^7.9.6": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.4.tgz#50129ac216b9a6a55b3853fdd923e74bf553a4c0" - integrity sha512-6vh4SqRuLLarjgeOf4EaROJAHjvu9Gl+/346PbDH9yWbJyfnJ/ah3jmYKYtswEyCoWZiidvVHjHshd4WgjB9BA== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" + integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" @@ -778,11 +778,12 @@ "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-proposal-optional-chaining@^7.9.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.4.tgz#750f1255e930a1f82d8cdde45031f81a0d0adff7" - integrity sha512-ZIhQIEeavTgouyMSdZRap4VPPHqJJ3NEs2cuHs5p0erH+iz6khB0qfgU8g7UuJkG88+fBMy23ZiU+nuHvekJeQ== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" + integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" "@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": @@ -1100,11 +1101,12 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-spread@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.4.tgz#4e2c85ea0d6abaee1b24dcfbbae426fe8d674cff" - integrity sha512-1e/51G/Ni+7uH5gktbWv+eCED9pP8ZpRhZB3jOaI3mmzfvJTWHkuyYTv0Z5PYtyM+Tr2Ccr9kUdQxn60fI5WuQ== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" + integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== dependencies: "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" "@babel/plugin-transform-sticky-regex@^7.8.3": version "7.10.4" @@ -1222,9 +1224,9 @@ regenerator-runtime "^0.13.4" "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" - integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.0.tgz#f10245877042a815e07f7e693faff0ae9d3a2aac" + integrity sha512-qArkXsjJq7H+T86WrIFV0Fnu/tNOkZ4cgXmjkzAu3b/58D5mFIO8JH/y77t7C9q0OdDRdh9s7Ue5GasYssxtXw== dependencies: regenerator-runtime "^0.13.4" @@ -1246,25 +1248,25 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.10.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.6": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.5.tgz#77ce464f5b258be265af618d8fddf0536f20b564" - integrity sha512-yc/fyv2gUjPqzTz0WHeRJH2pv7jA9kA7mBX2tXl/x5iOE81uaVPuGPtaYk7wmkx4b67mQ7NqI8rmT2pF47KYKQ== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.6": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" + integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== dependencies: "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.10.5" + "@babel/generator" "^7.11.0" "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" - "@babel/parser" "^7.10.5" - "@babel/types" "^7.10.5" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.11.0" + "@babel/types" "^7.11.0" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.6": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.5.tgz#d88ae7e2fde86bfbfe851d4d81afa70a997b5d15" - integrity sha512-ixV66KWfCI6GKoA/2H9v6bQdbfXEwwpOdQ8cRvb4F+eyvhlaHxWFMQB4+3d9QFJXZsiiiqVrewNV0DFEQpyT4Q== +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.6": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" + integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" @@ -1588,13 +1590,14 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@jest/types@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.1.0.tgz#f8afaaaeeb23b5cad49dd1f7779689941dcb6057" - integrity sha512-GXigDDsp6ZlNMhXQDeuy/iYCDsRIHJabWtDzvnn36+aqFfG14JmFV0e/iXxY4SP9vbXSiPNOWdehU5MeqrYHBQ== +"@jest/types@^26.2.0": + version "26.2.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.2.0.tgz#b28ca1fb517a4eb48c0addea7fcd9edc4ab45721" + integrity sha512-lvm3rJvctxd7+wxKSxxbzpDbr4FXDLaC57WEKdUIZ2cjTYuxYSc0zlyD7Z4Uqr5VdKxRUrtwIkiqBuvgf8uKJA== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^1.1.1" + "@types/node" "*" "@types/yargs" "^15.0.0" chalk "^4.0.0" @@ -2308,20 +2311,20 @@ integrity sha512-wqwhnJFyEwvzWQJjXrEt+7oBTSvu2qPbdYvUFYhDVzOJLWB5M7YEhDAkMrfHQJ0pZNBMGr580FqYue+XiURY0Q== "@ngneat/spectator@^5.11.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@ngneat/spectator/-/spectator-5.12.0.tgz#fe4752b75febb5797b7d3e2ba8167921b7adc756" - integrity sha512-q8F2eIp7uygnfBzn+2syGnYf4u9vDNT/WQSHAk+IffyPbQfM5EiPxPTY0vIccXg51zuZBPZVFtXMoFqN8zyglg== + version "5.13.0" + resolved "https://registry.yarnpkg.com/@ngneat/spectator/-/spectator-5.13.0.tgz#0a9720c3d3b60571c3619054f9831856997acf67" + integrity sha512-BlCmmgHMPtrdJECwctFmziRhHzSF3xxRnKiR/qJIerCd4csgpwGbhtEEh/2jnFEyLP6yLo4T4nCslwq3dHdFrQ== dependencies: "@testing-library/dom" "6.1.0" jquery "3.5.0" replace-in-file "^4.1.3" -"@ngtools/webpack@10.0.4": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-10.0.4.tgz#25c0a932319f8a26cbc849f4d13587f179fdc494" - integrity sha512-qzWkmVUUvr+2kiCtVLyopRwaBbExWtsGrgNVnJoAhtKKDflT4W33FpyJZJvxHwL6nfGGdb261Gfw7teIlCGjog== +"@ngtools/webpack@10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-10.0.5.tgz#8123647aa73463e586ac5792d16751a36d5caaaa" + integrity sha512-jMHfLXFzmgRlZbHgS71BEIKDyHbkfKrJL1sWEs3Ylox+TEIYzJiGfnem5ZGpr8wplz8HMMJ+xngtABePvc3/0w== dependencies: - "@angular-devkit/core" "10.0.4" + "@angular-devkit/core" "10.0.5" enhanced-resolve "4.1.1" rxjs "6.5.5" webpack-sources "1.4.3" @@ -2333,13 +2336,6 @@ dependencies: tslib "^1.9.0" -"@ngx-validate/core@^0.0.8", "@ngx-validate/core@^0.0.9": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@ngx-validate/core/-/core-0.0.8.tgz#8577405eb1af0f5002cdda7a86fbcda56280f116" - integrity sha512-caIG5ao76Xhf7T+pNA8crnpAwK0yqj3i0OAUGZRUq1W+kNgz+ZnrSd4F9an/W4g+38u/8gfUVvsfsm07ju6qYA== - dependencies: - tslib "^1.9.0" - "@ngxs/devtools-plugin@^3.6.2": version "3.6.2" resolved "https://registry.yarnpkg.com/@ngxs/devtools-plugin/-/devtools-plugin-3.6.2.tgz#aa0a4835f90fb905951d7712dc3ce508cbc15a2c" @@ -2559,21 +2555,21 @@ estree-walker "^1.0.1" picomatch "^2.2.2" -"@schematics/angular@10.0.4": - version "10.0.4" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-10.0.4.tgz#5a84fe6f4e8d8e4e7e2925c05b7689f70dab597f" - integrity sha512-wTpuVfPKALOcOHfD7Y222r/IfqJgpqASyoXdkzf7dZVrLXjNy/XrKuc2Vfn85Ce9lnme0xT5ww+KjbSRc0cSUw== +"@schematics/angular@10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-10.0.5.tgz#905f7c58547fdf9847fb004c1689bc0af7a09a7a" + integrity sha512-zg8QxgW3uLva/MSKMRYfV7dzj00SUki4nxYN4j1rw42VlwNPnFrPtzFVEilL6N7wFgoHP/6cZRgm4bfXYvLBvg== dependencies: - "@angular-devkit/core" "10.0.4" - "@angular-devkit/schematics" "10.0.4" + "@angular-devkit/core" "10.0.5" + "@angular-devkit/schematics" "10.0.5" -"@schematics/update@0.1000.4": - version "0.1000.4" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1000.4.tgz#e0780c5313ee90480f8a26b66c0104f664df64a4" - integrity sha512-NkIUsqnEqG6jhW6b1xXYmgW02WYAN9/IoswnZnaQrbGzxroNVQKURiV4AP22sZLCr7gQ9NJwjXxO5rxbzbY8wg== +"@schematics/update@0.1000.5": + version "0.1000.5" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.1000.5.tgz#7ce1012ee0b5fb88b149f84294eb49b911b01a3f" + integrity sha512-xodvq3X4B90u8myMEp9ESPnD2aC4YtNXj1FOcJ+BnguRA7q9rq9EL9Xqdef8sx3PObbSiKC0OFLyxgw76WuC3Q== dependencies: - "@angular-devkit/core" "10.0.4" - "@angular-devkit/schematics" "10.0.4" + "@angular-devkit/core" "10.0.5" + "@angular-devkit/schematics" "10.0.5" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" npm-package-arg "^8.0.0" @@ -2707,9 +2703,9 @@ "@types/istanbul-lib-report" "*" "@types/jasmine@^3.3.9": - version "3.5.11" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.11.tgz#ba8e80639dffbe277f49c708b45373a320d158e2" - integrity sha512-fg1rOd/DehQTIJTifGqGVY6q92lDgnLfs7C6t1ccSwQrMyoTGSoH6wWzhJDZb6ezhsdwAX4EIBLe8w5fXWmEng== + version "3.5.12" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.12.tgz#5c378c1545cdc7cb339cff5578f854b6d1e0a17d" + integrity sha512-vJaQ58oceFao+NzpKNqLOWwHPsqA7YEhKv+mOXvYU4/qh+BfVWIxaBtL0Ck5iCS67yOkNwGkDCrzepnzIWF+7g== "@types/jest@^25.2.3": version "25.2.3" @@ -3009,9 +3005,9 @@ JSONStream@^1.0.4, JSONStream@^1.3.4: through ">=2.2.7 <3" abab@^2.0.0, abab@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== + version "2.0.4" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.4.tgz#6dfa57b417ca06d21b2478f0e638302f99c2405c" + integrity sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ== abbrev@1: version "1.1.1" @@ -3045,9 +3041,9 @@ acorn@^6.0.1, acorn@^6.4.1: integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== acorn@^7.1.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== add-stream@^1.0.0: version "1.0.0" @@ -3109,7 +3105,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@6.12.3, ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3, ajv@^6.5.5: +ajv@6.12.3, ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.3: version "6.12.3" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== @@ -3458,13 +3454,13 @@ autoprefixer@9.8.0: postcss-value-parser "^4.1.0" autoprefixer@^9.6.5: - version "9.8.5" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.5.tgz#2c225de229ddafe1d1424c02791d0c3e10ccccaa" - integrity sha512-C2p5KkumJlsTHoNv9w31NrBRgXhf6eCMteJuHZi2xhkgC+5Vm40MEtCKPhc0qdgAOhox0YPy1SQHTAky05UoKg== + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== dependencies: browserslist "^4.12.0" - caniuse-lite "^1.0.30001097" - colorette "^1.2.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" normalize-range "^0.1.2" num2fraction "^1.2.2" postcss "^7.0.32" @@ -4099,10 +4095,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001061, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001097: - version "1.0.30001107" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001107.tgz#809360df7a5b3458f627aa46b0f6ed6d5239da9a" - integrity sha512-86rCH+G8onCmdN4VZzJet5uPELII59cUzDphko3thQFgAQG1RNa+sVLDoALIhRYmflo5iSIzWY3vu1XTWtNMQQ== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001032, caniuse-lite@^1.0.30001061, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001109: + version "1.0.30001110" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001110.tgz#9003e3c7f5a43ea6f1193d4d5acba0bfb152c71a" + integrity sha512-KqJWeat4rhSHF0ito4yz9q/JuZHkvn71SsBnxge4azjPDbowIjOUnS8i1xpKGxZxU6BFiPqO2hSV2eiCpFQVRw== canonical-path@1.0.0: version "1.0.0" @@ -4439,7 +4435,7 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.2" -colorette@^1.2.0: +colorette@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== @@ -5680,9 +5676,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.488: - version "1.3.512" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.512.tgz#620e6731c693ddaaf3750f23dde7f7c4347b7327" - integrity sha512-y02hdFg7c4jTfREcXf4fRhHLt7BzofMgd7JAKY+u9i62E0D1eIpLQPFo5/eboZL0bIVY9YHZA53+vCGNFREOXA== + version "1.3.518" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.518.tgz#c54ee9cf1a7bafd6e482a1a6cceac86448d941e8" + integrity sha512-IspiwXYDKZMxo+qc3Vof4WtwbG9BMDbJfati8PYj7uS4DJmJ67pwjCKZxlTBSAuCZSMcbRnj2Xz2H14uiKT7bQ== elliptic@^6.0.0, elliptic@^6.5.2: version "6.5.3" @@ -6830,11 +6826,11 @@ har-schema@^2.0.0: integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: - ajv "^6.5.5" + ajv "^6.12.3" har-schema "^2.0.0" hard-rejection@^2.1.0: @@ -7543,9 +7539,9 @@ is-directory@^0.3.1: integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= is-docker@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" - integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.0.tgz#25dc043e4fdc3cf969d622735e05a86ba9952e2b" + integrity sha512-mB2WygGsSeoXtLKpSYzP6sa0Z9DyU9ZyKlnvuZWxCociaI0qsF8u12sR72DFTX236g1u6oWSWYFuUk09nGQEjg== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" @@ -7718,9 +7714,9 @@ is-reference@^1.1.2: "@types/estree" "*" is-regex@^1.0.4, is-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" - integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== dependencies: has-symbols "^1.0.1" @@ -8228,11 +8224,12 @@ jest-snapshot@^25.5.1: semver "^6.3.0" jest-util@26.x: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.1.0.tgz#80e85d4ba820decacf41a691c2042d5276e5d8d8" - integrity sha512-rNMOwFQevljfNGvbzNQAxdmXQ+NawW/J72dmddsK0E8vgxXCMtwQ/EH0BiWEIxh0hhMcTsxwAxINt7Lh46Uzbg== + version "26.2.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.2.0.tgz#0597d2a27c559340957609f106c408c17c1d88ac" + integrity sha512-YmDwJxLZ1kFxpxPfhSJ0rIkiZOM0PQbRcfH0TzJOhqCisCAsI1WcmoQqO83My9xeVA2k4n+rzg2UuexVKzPpig== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.2.0" + "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^2.0.0" @@ -8290,10 +8287,11 @@ jest-worker@^25.5.0: supports-color "^7.0.0" jest-worker@^26.0.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.1.0.tgz#65d5641af74e08ccd561c240e7db61284f82f33d" - integrity sha512-Z9P5pZ6UC+kakMbNJn+tA2RdVdNX5WH1x+5UCBZ9MxIK24pjYtFt96fK+UwBTrjLYm232g1xz0L3eTh51OW+yQ== + version "26.2.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.2.1.tgz#5d630ab93f666b53f911615bc13e662b382bd513" + integrity sha512-+XcGMMJDTeEGncRb5M5Zq9P7K4sQ1sirhjdOxsN1462h6lFo9w59bl2LVQmdGEEeU3m+maZCkS2Tcc9SfCHO4A== dependencies: + "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" @@ -9893,9 +9891,9 @@ onetime@^2.0.0: mimic-fn "^1.0.0" onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + version "5.1.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.1.tgz#5c8016847b0d67fcedb7eef254751cfcdc7e9418" + integrity sha512-ZpZpjcJeugQfWsfyQlshVoowIIQ1qBGSVll4rfDq6JJVO//fesjoX808hXWfBjY+ROZgpKDI5TRSRBSoJiZ8eg== dependencies: mimic-fn "^2.1.0" @@ -10864,11 +10862,11 @@ pretty-format@^25.2.1, pretty-format@^25.5.0: react-is "^16.12.0" pretty-format@^26.0.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.1.0.tgz#272b9cd1f1a924ab5d443dc224899d7a65cb96ec" - integrity sha512-GmeO1PEYdM+non4BKCj+XsPJjFOJIPnsLewqhDVoqY1xo0yNmDas7tC2XwpMrRAHR3MaE2hPo37deX5OisJ2Wg== + version "26.2.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.2.0.tgz#83ecc8d7de676ff224225055e72bd64821cec4f1" + integrity sha512-qi/8IuBu2clY9G7qCXgCdD1Bf9w+sXakdHTRToknzMtVy0g7c4MBWaZy7MfB7ndKZovRO6XRwJiAYqq+MC7SDA== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.2.0" ansi-regex "^5.0.0" ansi-styles "^4.0.0" react-is "^16.12.0" @@ -11741,9 +11739,9 @@ rxjs@6.5.5, rxjs@~6.5.4: tslib "^1.9.0" rxjs@^6.4.0, rxjs@^6.5.0, rxjs@^6.5.2, rxjs@^6.5.3: - version "6.6.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.0.tgz#af2901eedf02e3a83ffa7f886240ff9018bbec84" - integrity sha512-3HMA8z/Oz61DUHe+SdOiQyzIf4tOx5oQHmMir7IZEu6TMqCLHT4LRcmNaUS0NwOz8VLvmmBduMsoaUvMaIiqzg== + version "6.6.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" + integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== dependencies: tslib "^1.9.0" @@ -13094,9 +13092,9 @@ ts-pnp@^1.1.6: integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== ts-toolbelt@^6.9.9: - version "6.13.34" - resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.13.34.tgz#3bd6e1e333a75c5ddab584d293f35494cb8c9222" - integrity sha512-ikZwSUPO+fW+OUnyER1KCG58khTi51Di3+iVdhkK7UshqkL0Ir749B2TQ44o/khkKvDSOMzF8NuVkQLycDXnsg== + version "6.13.39" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.13.39.tgz#80541ce39b595a42be5ddd04e3e6df65597774f8" + integrity sha512-VD/rJ6+NGFA7AK2KWmGzLifrqA060M9o7+R2BxJtLBlwmfEaGdqGeyUPRDKhMZPMgpT/JMQ6+X+/ppaZNzuhvw== tsickle@^0.38.1: version "0.38.1" @@ -13108,15 +13106,15 @@ tslib@2.0.0, tslib@^2.0.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== -tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.10.0, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== tslint@~6.1.0: - version "6.1.2" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.2.tgz#2433c248512cc5a7b2ab88ad44a6b1b34c6911cf" - integrity sha512-UyNrLdK3E0fQG/xWNqAFAC5ugtFyPO4JJR1KyyfQAyzR8W0fTRrC91A8Wej4BntFzcvETdCSDa/4PnNYJQLYiA== + version "6.1.3" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" + integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== dependencies: "@babel/code-frame" "^7.0.0" builtin-modules "^1.1.1" @@ -13129,7 +13127,7 @@ tslint@~6.1.0: mkdirp "^0.5.3" resolve "^1.3.2" semver "^5.3.0" - tslib "^1.10.0" + tslib "^1.13.0" tsutils "^2.29.0" tsutils@^2.29.0: @@ -13229,9 +13227,9 @@ typescript@^3.5.2, typescript@~3.9.5: integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== uglify-js@^3.1.4: - version "3.10.0" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.0.tgz#397a7e6e31ce820bfd1cb55b804ee140c587a9e7" - integrity sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA== + version "3.10.1" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.1.tgz#dd14767eb7150de97f2573a5ff210db14fffe4ad" + integrity sha512-RjxApKkrPJB6kjJxQS3iZlf///REXWYxYJxO/MpmlQzVkDWVI3PSnCBWezMecmTU/TRkNxrl8bmsfFQCp+LO+Q== uid-number@0.0.6: version "0.0.6" From 5e97c31ce94391dfe53be4f6697a006a25092f73 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Tue, 4 Aug 2020 17:21:06 +0300 Subject: [PATCH 12/20] fix: correct the base urls --- templates/app/angular/src/environments/environment.prod.ts | 2 +- .../projects/dev-app/src/environments/environment.prod.ts | 2 +- .../angular/projects/dev-app/src/environments/environment.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/app/angular/src/environments/environment.prod.ts b/templates/app/angular/src/environments/environment.prod.ts index b5e65817d2..cfe0401dee 100644 --- a/templates/app/angular/src/environments/environment.prod.ts +++ b/templates/app/angular/src/environments/environment.prod.ts @@ -3,7 +3,7 @@ import { Config } from '@abp/ng.core'; export const environment = { production: true, application: { - baseUrl: 'https://localhost:4200/', + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, diff --git a/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts b/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts index 403476b62c..e7750a4873 100644 --- a/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts +++ b/templates/module/angular/projects/dev-app/src/environments/environment.prod.ts @@ -3,7 +3,7 @@ import { Config } from '@abp/ng.core'; export const environment = { production: true, application: { - baseUrl: 'https://localhost:4200/', + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, diff --git a/templates/module/angular/projects/dev-app/src/environments/environment.ts b/templates/module/angular/projects/dev-app/src/environments/environment.ts index 4102abb202..780fa891d9 100644 --- a/templates/module/angular/projects/dev-app/src/environments/environment.ts +++ b/templates/module/angular/projects/dev-app/src/environments/environment.ts @@ -3,7 +3,7 @@ import { Config } from '@abp/ng.core'; export const environment = { production: false, application: { - baseUrl: 'https://localhost:4200/', + baseUrl: 'http://localhost:4200/', name: 'MyProjectName', logoUrl: '', }, From e73ceb766f72badfe3ddaa0b12da38d4d4c9c313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Arman=20=C3=96zak?= Date: Wed, 5 Aug 2020 08:48:15 +0300 Subject: [PATCH 13/20] Update find-tenant-result-dto.ts --- .../core/src/lib/models/find-tenant-result-dto.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts b/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts index 751a9dc87a..9b1b0cc4b6 100644 --- a/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts +++ b/npm/ng-packs/packages/core/src/lib/models/find-tenant-result-dto.ts @@ -5,11 +5,9 @@ export class FindTenantResultDto { name: string; constructor(initialValues: Partial = {}) { - if (initialValues) { - for (const key in initialValues) { - if (initialValues.hasOwnProperty(key)) { - this[key] = initialValues[key]; - } + for (const key in initialValues) { + if (initialValues.hasOwnProperty(key)) { + this[key] = initialValues[key]; } } } From 323a5c4965c5d2fca67953baac294c9f721575a8 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 5 Aug 2020 11:42:46 +0300 Subject: [PATCH 14/20] docs: add alt texts to images --- docs/en/UI/Angular/Multi-Tenancy.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/en/UI/Angular/Multi-Tenancy.md b/docs/en/UI/Angular/Multi-Tenancy.md index c71d26adc4..94b3954a03 100644 --- a/docs/en/UI/Angular/Multi-Tenancy.md +++ b/docs/en/UI/Angular/Multi-Tenancy.md @@ -3,9 +3,7 @@ ABP Angular UI supports the multi-tenancy. The following features related to multi-tenancy are available in the startup templates. -

- -

+![Tenants Page](./images/tenants-page.png)

Tenants page

On the page above, you can; @@ -16,9 +14,7 @@ On the page above, you can; - Delete a tenant. -

- -

+![Tenant Switching Component](./images/tenant-switching-box.png)

Tenant Switching Component

You can switch between existing tenants by using the tenant switching component in the child pages of the `AccountLayoutComponent` (like Login page). Angular UI sends the selected tenant id sends to the backend as `__tenant` header on each request. From 931442d1afed1af608e00caf9afcf4465d6bfa4d Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 5 Aug 2020 14:05:29 +0300 Subject: [PATCH 15/20] feat: create OAuthConfigurationHandler --- .../packages/core/src/lib/handlers/index.ts | 1 + .../handlers/oauth-configuration.handler.ts | 35 +++++++++++++++++++ .../core/src/lib/states/config.state.ts | 11 ++---- 3 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/handlers/oauth-configuration.handler.ts diff --git a/npm/ng-packs/packages/core/src/lib/handlers/index.ts b/npm/ng-packs/packages/core/src/lib/handlers/index.ts index b666218d93..e11b317f45 100644 --- a/npm/ng-packs/packages/core/src/lib/handlers/index.ts +++ b/npm/ng-packs/packages/core/src/lib/handlers/index.ts @@ -1 +1,2 @@ +export * from './oauth-configuration.handler'; export * from './routes.handler'; diff --git a/npm/ng-packs/packages/core/src/lib/handlers/oauth-configuration.handler.ts b/npm/ng-packs/packages/core/src/lib/handlers/oauth-configuration.handler.ts new file mode 100644 index 0000000000..d9c6806900 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/handlers/oauth-configuration.handler.ts @@ -0,0 +1,35 @@ +import { Inject, Injectable } from '@angular/core'; +import { Actions, ofActionSuccessful } from '@ngxs/store'; +import { OAuthService } from 'angular-oauth2-oidc'; +import compare from 'just-compare'; +import { filter, map } from 'rxjs/operators'; +import { SetEnvironment } from '../actions/config.actions'; +import { ABP } from '../models/common'; +import { CORE_OPTIONS } from '../tokens/options.token'; + +@Injectable({ + providedIn: 'root', +}) +export class OAuthConfigurationHandler { + constructor( + private actions: Actions, + private oAuthService: OAuthService, + @Inject(CORE_OPTIONS) private options: ABP.Root, + ) { + this.oAuthService.configure(this.options.environment.oAuthConfig); + + this.listenToSetEnvironment(); + } + + private listenToSetEnvironment() { + this.actions + .pipe(ofActionSuccessful(SetEnvironment)) + .pipe( + map(({ environment }: SetEnvironment) => environment.oAuthConfig), + filter(config => !compare(config, this.options.environment.oAuthConfig)), + ) + .subscribe(config => { + this.oAuthService.configure(config); + }); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 1134c85bce..25c77499d3 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -10,9 +10,6 @@ import { SetLanguage } from '../actions/session.actions'; import { ApplicationConfiguration } from '../models/application-configuration'; import { Config } from '../models/config'; import { SessionState } from './session.state'; -import compare from 'just-compare'; -import clone from 'just-clone'; -import { OAuthService } from 'angular-oauth2-oidc'; @State({ name: 'ConfigState', @@ -32,7 +29,7 @@ export class ConfigState { static getOne(key: string) { const selector = createSelector([ConfigState], (state: Config.State) => { - return clone(state[key]); + return state[key]; }); return selector; @@ -197,7 +194,7 @@ export class ConfigState { return selector; } - constructor(private http: HttpClient, private store: Store, private oAuthService: OAuthService) {} + constructor(private http: HttpClient, private store: Store) {} @Action(GetAppConfiguration) addData({ patchState, dispatch }: StateContext) { @@ -241,10 +238,6 @@ export class ConfigState { ) { const { oAuthConfig } = getState().environment; - if (!compare(oAuthConfig, environment.oAuthConfig)) { - this.oAuthService.configure(environment.oAuthConfig); - } - return patchState({ environment, }); From 18d6a9ec8e4e90ebf7840e368010a501b9e4fda4 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 5 Aug 2020 14:05:58 +0300 Subject: [PATCH 16/20] refactor: improve code readability --- .../packages/core/src/lib/core.module.ts | 7 +- .../core/src/lib/tests/initial-utils.spec.ts | 22 +-- .../src/lib/tests/multi-tenancy-utils.spec.ts | 18 +- .../utils/formatted-string-value-extractor.ts | 156 ------------------ .../core/src/lib/utils/initial-utils.ts | 10 -- .../core/src/lib/utils/multi-tenancy-utils.ts | 23 +-- 6 files changed, 28 insertions(+), 208 deletions(-) delete mode 100644 npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts diff --git a/npm/ng-packs/packages/core/src/lib/core.module.ts b/npm/ng-packs/packages/core/src/lib/core.module.ts index 16295b5abf..85cf87297f 100644 --- a/npm/ng-packs/packages/core/src/lib/core.module.ts +++ b/npm/ng-packs/packages/core/src/lib/core.module.ts @@ -21,6 +21,7 @@ import { PermissionDirective } from './directives/permission.directive'; import { ReplaceableTemplateDirective } from './directives/replaceable-template.directive'; import { StopPropagationDirective } from './directives/stop-propagation.directive'; import { VisibilityDirective } from './directives/visibility.directive'; +import { OAuthConfigurationHandler } from './handlers/oauth-configuration.handler'; import { RoutesHandler } from './handlers/routes.handler'; import { ApiInterceptor } from './interceptors/api.interceptor'; import { LocalizationModule } from './localization.module'; @@ -37,7 +38,7 @@ import { SessionState } from './states/session.state'; import { coreOptionsFactory, CORE_OPTIONS } from './tokens/options.token'; import { noop } from './utils/common-utils'; import './utils/date-extensions'; -import { configureOAuth, getInitialData, localeInitializer } from './utils/initial-utils'; +import { getInitialData, localeInitializer } from './utils/initial-utils'; export function storageFactory(): OAuthStorage { return localStorage; @@ -187,8 +188,8 @@ export class CoreModule { { provide: APP_INITIALIZER, multi: true, - deps: [Injector, NGXS_CONFIG_PLUGIN_OPTIONS], - useFactory: configureOAuth, + deps: [OAuthConfigurationHandler], + useFactory: noop, }, { provide: APP_INITIALIZER, diff --git a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts index f1417eae2f..ae9ce94650 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts @@ -1,10 +1,11 @@ import { Component, Injector } from '@angular/core'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; +import { OAuthService } from 'angular-oauth2-oidc'; import { of } from 'rxjs'; import { GetAppConfiguration } from '../actions'; -import { getInitialData, localeInitializer, configureOAuth, checkAccessToken } from '../utils'; -import { OAuthService } from 'angular-oauth2-oidc'; +import { CORE_OPTIONS } from '../tokens/options.token'; +import { checkAccessToken, getInitialData, localeInitializer } from '../utils'; import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; @Component({ @@ -18,24 +19,13 @@ describe('InitialUtils', () => { const createComponent = createComponentFactory({ component: DummyComponent, mocks: [Store, OAuthService], + providers: [ + { provide: CORE_OPTIONS, useValue: { environment: { oAuthConfig: { issuer: 'test' } } } }, + ], }); beforeEach(() => (spectator = createComponent())); - describe('#configureOAuth', () => { - test('should be called the the configure method of OAuthService', async () => { - const injector = spectator.inject(Injector); - const injectorSpy = jest.spyOn(injector, 'get'); - const oAuth = spectator.inject(OAuthService); - const configureSpy = jest.spyOn(oAuth, 'configure'); - - injectorSpy.mockReturnValueOnce(oAuth); - - await configureOAuth(injector, { environment: { oAuthConfig: { issuer: 'test' } } })(); - expect(configureSpy).toHaveBeenCalledWith({ issuer: 'test' }); - }); - }); - describe('#getInitialData', () => { test('should dispatch GetAppConfiguration and return', async () => { const injector = spectator.inject(Injector); diff --git a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts index bfff03f7e6..6d8b3d6941 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts @@ -1,12 +1,11 @@ import { Component, Injector } from '@angular/core'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { Store } from '@ngxs/store'; -import { MultiTenancyService } from '../services/multi-tenancy.service'; -import { parseTenantFromUrl, getCurrentTenancyNameOrNull } from '../utils'; -import * as multiTenancyUtils from '../utils/multi-tenancy-utils'; -import { of, Subject, BehaviorSubject } from 'rxjs'; -import { FindTenantResultDto } from '../models/find-tenant-result-dto'; import clone from 'just-clone'; +import { BehaviorSubject } from 'rxjs'; +import { FindTenantResultDto } from '../models/find-tenant-result-dto'; +import { MultiTenancyService } from '../services/multi-tenancy.service'; +import { getCurrentTenancyName, parseTenantFromUrl } from '../utils'; const environment = { production: false, @@ -59,16 +58,17 @@ describe('MultiTenancyUtils', () => { beforeEach(() => (spectator = createComponent())); - describe('#getCurrentTenancyNameOrNull', () => { + describe('#getCurrentTenancyName', () => { test('should get tenancy name from href', async () => { setHref('https://abp.volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{0}.volosoft.com')).toBe('abp'); + expect(getCurrentTenancyName('https://{0}.volosoft.com')).toBe('abp'); setHref('https://volosoft.com/'); - expect(getCurrentTenancyNameOrNull('https://{0}.com')).toBe('volosoft'); + expect(getCurrentTenancyName('https://{0}.com')).toBe('volosoft'); setHref('https://volosoft.com/abp/'); - expect(getCurrentTenancyNameOrNull('https://volosoft.com/{0}')).toBe('abp'); + expect(getCurrentTenancyName('https://volosoft.com/{0}')).toBe('abp'); + expect(getCurrentTenancyName('https://volosoft.com')).toBe(undefined); }); }); diff --git a/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts b/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts deleted file mode 100644 index 7e9e3f00da..0000000000 --- a/npm/ng-packs/packages/core/src/lib/utils/formatted-string-value-extractor.ts +++ /dev/null @@ -1,156 +0,0 @@ -class ExtractionResult { - public isMatch: boolean; - public matches: any[]; - - constructor(isMatch: boolean) { - this.isMatch = isMatch; - this.matches = []; - } -} - -enum FormatStringTokenType { - ConstantText, - DynamicValue, -} - -class FormatStringToken { - public text: string; - public type: FormatStringTokenType; - - constructor(text: string, type: FormatStringTokenType) { - this.text = text; - this.type = type; - } -} - -class FormatStringTokenizer { - tokenize(format: string, includeBracketsForDynamicValues: boolean = false): FormatStringToken[] { - const tokens: FormatStringToken[] = []; - - let currentText = ''; - let inDynamicValue = false; - - for (let i = 0; i < format.length; i++) { - const c = format[i]; - switch (c) { - case '{': - if (inDynamicValue) { - throw new Error( - 'Incorrect syntax at char ' + - i + - '! format string can not contain nested dynamic value expression!', - ); - } - - inDynamicValue = true; - - if (currentText.length > 0) { - tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); - currentText = ''; - } - - break; - case '}': - if (!inDynamicValue) { - throw new Error( - 'Incorrect syntax at char ' + - i + - '! These is no opening brackets for the closing bracket }.', - ); - } - - inDynamicValue = false; - - if (currentText.length <= 0) { - throw new Error( - 'Incorrect syntax at char ' + i + '! Brackets does not containt any chars.', - ); - } - - let dynamicValue = currentText; - if (includeBracketsForDynamicValues) { - dynamicValue = '{' + dynamicValue + '}'; - } - - tokens.push(new FormatStringToken(dynamicValue, FormatStringTokenType.DynamicValue)); - currentText = ''; - - break; - default: - currentText += c; - break; - } - } - - if (inDynamicValue) { - throw new Error('There is no closing } char for an opened { char.'); - } - - if (currentText.length > 0) { - tokens.push(new FormatStringToken(currentText, FormatStringTokenType.ConstantText)); - } - - return tokens; - } -} - -export class FormattedStringValueExtractor { - extract(str: string, format: string): ExtractionResult { - if (str === format) { - return new ExtractionResult(true); - } - - const formatTokens = new FormatStringTokenizer().tokenize(format); - if (!formatTokens) { - return new ExtractionResult(str === ''); - } - - const result = new ExtractionResult(true); - - for (let i = 0; i < formatTokens.length; i++) { - const currentToken = formatTokens[i]; - const previousToken = i > 0 ? formatTokens[i - 1] : null; - - if (currentToken.type === FormatStringTokenType.ConstantText) { - if (i === 0) { - if (str.indexOf(currentToken.text) !== 0) { - result.isMatch = false; - return result; - } - - str = str.substr(currentToken.text.length, str.length - currentToken.text.length); - } else { - const matchIndex = str.indexOf(currentToken.text); - if (matchIndex < 0) { - result.isMatch = false; - return result; - } - - result.matches.push({ name: previousToken.text, value: str.substr(0, matchIndex) }); - str = str.substring(0, matchIndex + currentToken.text.length); - } - } - } - - const lastToken = formatTokens[formatTokens.length - 1]; - if (lastToken.type === FormatStringTokenType.DynamicValue) { - result.matches.push({ name: lastToken.text, value: str }); - } - - return result; - } - - isMatch(str: string, format: string): string[] { - const result = new FormattedStringValueExtractor().extract(str, format); - if (!result.isMatch) { - return []; - } - - const values = []; - for (let i = 0; i < result.matches.length; i++) { - values.push(result.matches[i].value); - } - - return values; - } -} diff --git a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts index d9c8ae163b..b0adfd4980 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/initial-utils.ts @@ -9,16 +9,6 @@ import { ConfigState } from '../states/config.state'; import { CORE_OPTIONS } from '../tokens/options.token'; import { parseTenantFromUrl } from './multi-tenancy-utils'; -export function configureOAuth(injector: Injector, options: ABP.Root) { - const fn = () => { - const oAuth = injector.get(OAuthService); - oAuth.configure(options.environment.oAuthConfig); - return Promise.resolve(); - }; - - return fn; -} - export function getInitialData(injector: Injector) { const fn = async () => { const store: Store = injector.get(Store); diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index 58801fbcb3..fae20ef614 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -5,24 +5,17 @@ import { SetEnvironment } from '../actions'; import { Config } from '../models/config'; import { MultiTenancyService } from '../services/multi-tenancy.service'; import { ConfigState } from '../states/config.state'; -import { FormattedStringValueExtractor } from './formatted-string-value-extractor'; +import clone from 'just-clone'; const tenancyPlaceholder = '{0}'; -export function getCurrentTenancyNameOrNull(appBaseUrl: string): string { - if (appBaseUrl.indexOf(tenancyPlaceholder) < 0) return null; - +export function getCurrentTenancyName(appBaseUrl: string): string { if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; const currentRootAddress = window.location.href; - const formattedStringValueExtractor = new FormattedStringValueExtractor(); - const values = formattedStringValueExtractor.isMatch(currentRootAddress, appBaseUrl); - if (!values.length) { - return null; - } - - return values[0]; + const regex = appBaseUrl.replace(/\./g, '.').replace(tenancyPlaceholder, '(.+)'); + return (currentRootAddress.match(regex) || []).slice(1)[0]; } export async function parseTenantFromUrl(injector: Injector) { @@ -31,7 +24,7 @@ export async function parseTenantFromUrl(injector: Injector) { const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; const { baseUrl = '' } = environment.application; - const tenancyName = getCurrentTenancyNameOrNull(baseUrl); + const tenancyName = getCurrentTenancyName(baseUrl); if (tenancyName) { multiTenancyService.isTenantBoxVisible = false; @@ -51,8 +44,10 @@ export async function parseTenantFromUrl(injector: Injector) { return Promise.resolve(); } -export function setEnvironment(store: Store, tenancyName: string) { - const environment = store.selectSnapshot(ConfigState.getOne('environment')) as Config.Environment; +function setEnvironment(store: Store, tenancyName: string) { + const environment = clone( + store.selectSnapshot(ConfigState.getOne('environment')), + ) as Config.Environment; if (environment.application.baseUrl) { environment.application.baseUrl = environment.application.baseUrl.replace( From 6d6d2e11ba9fca08175fd94a043c6815d5d39c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Levent=20Arman=20=C3=96zak?= Date: Wed, 5 Aug 2020 14:12:38 +0300 Subject: [PATCH 17/20] remove unused variables --- .../packages/core/src/lib/states/config.state.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts index 25c77499d3..2aaf7a3bc2 100644 --- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts +++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts @@ -232,14 +232,7 @@ export class ConfigState { } @Action(SetEnvironment) - setEnvironment( - { getState, patchState }: StateContext, - { environment }: SetEnvironment, - ) { - const { oAuthConfig } = getState().environment; - - return patchState({ - environment, - }); + setEnvironment({ patchState }: StateContext, { environment }: SetEnvironment) { + return patchState({ environment }); } } From ca190286009ac3bbdb1309443784851b63de2790 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 5 Aug 2020 14:37:50 +0300 Subject: [PATCH 18/20] test: fix testing error --- .../packages/core/src/lib/tests/config.state.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts index 7ad22f8ab6..e30a55635b 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/config.state.spec.ts @@ -6,7 +6,6 @@ import { SetLanguage } from '../actions'; import { Config } from '../models/config'; import { ApplicationConfigurationService, ConfigStateService } from '../services'; import { ConfigState } from '../states'; -import { OAuthService } from 'angular-oauth2-oidc'; export const CONFIG_STATE_DATA = { environment: { @@ -108,14 +107,14 @@ describe('ConfigState', () => { const createService = createServiceFactory({ service: ConfigStateService, - mocks: [ApplicationConfigurationService, Store, HttpClient, OAuthService], + mocks: [ApplicationConfigurationService, Store, HttpClient], }); beforeEach(() => { spectator = createService(); store = spectator.inject(Store); service = spectator.service; - state = new ConfigState(spectator.inject(HttpClient), store, spectator.inject(OAuthService)); + state = new ConfigState(spectator.inject(HttpClient), store); }); describe('#getAll', () => { From 665b8afcbf7eae4f19ae90beb5cdeb97fefecaff Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Wed, 5 Aug 2020 15:37:26 +0300 Subject: [PATCH 19/20] feat: add createTokenParser string util --- .../core/src/lib/tests/string-utils.spec.ts | 22 +++++++++++++++++++ .../packages/core/src/lib/utils/index.ts | 3 ++- .../core/src/lib/utils/string-utils.ts | 17 ++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts create mode 100644 npm/ng-packs/packages/core/src/lib/utils/string-utils.ts diff --git a/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts new file mode 100644 index 0000000000..a0642e43ee --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts @@ -0,0 +1,22 @@ +import { createTokenParser } from '../utils/string-utils'; + +describe('String Utils', () => { + describe('#createTokenParser', () => { + const parseTokens = createTokenParser('{subDomain}.{domain}.{gtld}|{domain}.{gtld}'); + + test.each` + url | subDomain | domain | gtld + ${'www.example.com'} | ${'www'} | ${'example'} | ${'com'} + ${'test.sub.example.com'} | ${'test.sub'} | ${'example'} | ${'com'} + ${'example.com'} | ${undefined} | ${'example'} | ${'com'} + `( + 'should return subDomain as $subDomain, domain as $domain, and gtld as $gtld when url is $url', + ({ url, subDomain, domain, gtld }) => { + const parsed = parseTokens(url); + expect(parsed.subDomain[0]).toBe(subDomain); + expect(parsed.domain[0]).toBe(domain); + expect(parsed.gtld[0]).toBe(gtld); + }, + ); + }); +}); diff --git a/npm/ng-packs/packages/core/src/lib/utils/index.ts b/npm/ng-packs/packages/core/src/lib/utils/index.ts index b31c0320f1..9949fa9f26 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/index.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/index.ts @@ -6,8 +6,9 @@ export * from './generator-utils'; export * from './initial-utils'; export * from './lazy-load-utils'; export * from './localization-utils'; +export * from './multi-tenancy-utils'; export * from './number-utils'; export * from './route-utils'; export * from './rxjs-utils'; -export * from './multi-tenancy-utils'; +export * from './string-utils'; export * from './tree-utils'; diff --git a/npm/ng-packs/packages/core/src/lib/utils/string-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/string-utils.ts new file mode 100644 index 0000000000..00db697325 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/utils/string-utils.ts @@ -0,0 +1,17 @@ +export function createTokenParser(format: string) { + return (string: string) => { + const tokens: string[] = []; + const regex = format.replace(/\./g, '\\.').replace(/\{\s?([0-9a-zA-Z]+)\s?\}/g, (_, token) => { + tokens.push(token); + return '(.+)'; + }); + + const matches = (string.match(regex) || []).slice(1); + + return matches.reduce((acc, v, i) => { + const key = tokens[i]; + acc[key] = [...(acc[key] || []), v].filter(Boolean); + return acc; + }, {} as Record); + }; +} From 97ab8dc7d32943bf3e4e98104e5fe3dba0f74c44 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Wed, 5 Aug 2020 15:47:16 +0300 Subject: [PATCH 20/20] feat: use createTokenParser in multi tenancy utils --- .../src/lib/tests/multi-tenancy-utils.spec.ts | 16 +--------------- .../core/src/lib/utils/multi-tenancy-utils.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts index 6d8b3d6941..f802e22371 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts @@ -5,7 +5,7 @@ import clone from 'just-clone'; import { BehaviorSubject } from 'rxjs'; import { FindTenantResultDto } from '../models/find-tenant-result-dto'; import { MultiTenancyService } from '../services/multi-tenancy.service'; -import { getCurrentTenancyName, parseTenantFromUrl } from '../utils'; +import { parseTenantFromUrl } from '../utils'; const environment = { production: false, @@ -58,20 +58,6 @@ describe('MultiTenancyUtils', () => { beforeEach(() => (spectator = createComponent())); - describe('#getCurrentTenancyName', () => { - test('should get tenancy name from href', async () => { - setHref('https://abp.volosoft.com/'); - expect(getCurrentTenancyName('https://{0}.volosoft.com')).toBe('abp'); - - setHref('https://volosoft.com/'); - expect(getCurrentTenancyName('https://{0}.com')).toBe('volosoft'); - - setHref('https://volosoft.com/abp/'); - expect(getCurrentTenancyName('https://volosoft.com/{0}')).toBe('abp'); - expect(getCurrentTenancyName('https://volosoft.com')).toBe(undefined); - }); - }); - describe('#parseTenantFromUrl', () => { test('should get the tenancyName, set replaced environment and call the findTenantByName method of MultiTenancyService', async () => { const injector = spectator.inject(Injector); diff --git a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts index fae20ef614..6ba6c9e683 100644 --- a/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts +++ b/npm/ng-packs/packages/core/src/lib/utils/multi-tenancy-utils.ts @@ -1,21 +1,21 @@ import { Injector } from '@angular/core'; import { Store } from '@ngxs/store'; +import clone from 'just-clone'; import { switchMap, tap } from 'rxjs/operators'; import { SetEnvironment } from '../actions'; import { Config } from '../models/config'; import { MultiTenancyService } from '../services/multi-tenancy.service'; import { ConfigState } from '../states/config.state'; -import clone from 'just-clone'; +import { createTokenParser } from './string-utils'; const tenancyPlaceholder = '{0}'; -export function getCurrentTenancyName(appBaseUrl: string): string { +function getCurrentTenancyName(appBaseUrl: string): string { if (appBaseUrl.charAt(appBaseUrl.length - 1) !== '/') appBaseUrl += '/'; - const currentRootAddress = window.location.href; - - const regex = appBaseUrl.replace(/\./g, '.').replace(tenancyPlaceholder, '(.+)'); - return (currentRootAddress.match(regex) || []).slice(1)[0]; + const parseTokens = createTokenParser(appBaseUrl); + const token = tenancyPlaceholder.replace(/[}{]/g, ''); + return parseTokens(window.location.href)[token][0]; } export async function parseTenantFromUrl(injector: Injector) {