From de747c4c151d838245fa8e23743cad3031e9365d Mon Sep 17 00:00:00 2001 From: Kyusung4698 Date: Tue, 4 Feb 2020 21:34:47 +0100 Subject: [PATCH] 0.5.13 (2020-02-04) * add divination card header * add delay before registering hotkeys after showing window (#177) * update pseudo mod behaviour * use pseudo value instead of single value (#182) * remove stat from list if used as pseudo stat (#175) * increase command throttle time (#188) * fix authenticated request hitting rate limit (#185) * fix exchange rate using 6L if no links are present (#187) --- CHANGELOG.md | 11 ++ README.md | 6 +- package.json | 2 +- .../data/poe/service/trade-http.service.ts | 16 ++- .../layout/page/overlay/overlay.component.ts | 102 ++++++++++-------- .../command/service/command.service.ts | 4 +- .../evaluate/evaluate.component.scss | 1 + .../item-frame-header.component.scss | 10 ++ .../shared/module/poe/config/pseudo.config.ts | 84 +++++++-------- .../poe/service/item/item-evaluate.service.ts | 6 +- .../parser/item-post-parser-pseudo.service.ts | 14 ++- .../item-section-properties-parser.service.ts | 8 +- src/assets/poe/item/header-card-left.png | Bin 0 -> 1212 bytes src/assets/poe/item/header-card-middle.png | Bin 0 -> 1111 bytes src/assets/poe/item/header-card-right.png | Bin 0 -> 1219 bytes 15 files changed, 158 insertions(+), 106 deletions(-) create mode 100644 src/assets/poe/item/header-card-left.png create mode 100644 src/assets/poe/item/header-card-middle.png create mode 100644 src/assets/poe/item/header-card-right.png diff --git a/CHANGELOG.md b/CHANGELOG.md index fefbc323..a3899a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## 0.5.13 (2020-02-04) + +* add divination card header +* add delay before registering hotkeys after showing window (#177) +* update pseudo mod behaviour + * use pseudo value instead of single value (#182) + * remove stat from list if used as pseudo stat (#175) +* increase command throttle time (#188) +* fix authenticated request hitting rate limit (#185) +* fix exchange rate using 6L if no links are present (#187) + ## 0.5.12 (2020-02-03) * add kakao client support (#181) diff --git a/README.md b/README.md index 7f5ffc13..c3a85877 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# PoE Overlay 0.5.12 +# PoE Overlay 0.5.13 An Overlay for Path of Exile. The ***core aspect*** is to blend in with the game. Built with Electron and Angular. @@ -79,9 +79,9 @@ These instructions will set you up to run and enjoy the overlay. 1. Head over to [Releases](https://github.com/Kyusung4698/PoE-Overlay/releases) and download the latest zip 2. Extract zip -3. Run `poe-overlay 0.5.12.exe` +3. Run `poe-overlay 0.5.13.exe` 4. Start Path of Exile -5. Wait until you can see `POE Overlay 0.5.12` in the bottom left corner +5. Wait until you can see `POE Overlay 0.5.13` in the bottom left corner 6. Hit `f7` and set `Language` and `League` to meet your game settings #### Shortcuts diff --git a/package.json b/package.json index 1362fe68..30c87869 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "author": { "name": "Kyusung4698" }, - "version": "0.5.12", + "version": "0.5.13", "scripts": { "postinstall": "electron-builder install-app-deps", "ng:serve": "ng serve", diff --git a/src/app/data/poe/service/trade-http.service.ts b/src/app/data/poe/service/trade-http.service.ts index 4f84ccba..a48eec1b 100644 --- a/src/app/data/poe/service/trade-http.service.ts +++ b/src/app/data/poe/service/trade-http.service.ts @@ -1,12 +1,13 @@ -import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse, HttpParams, HttpResponse } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from '@env/environment'; import { Language } from '@shared/module/poe/type'; -import { Observable } from 'rxjs'; -import { map, retry } from 'rxjs/operators'; +import { Observable, of, throwError } from 'rxjs'; +import { delay, flatMap, map, retry, retryWhen } from 'rxjs/operators'; import { TradeFetchResult, TradeItemsResult, TradeLeaguesResult, TradeResponse, TradeSearchRequest, TradeSearchResponse, TradeStaticResult, TradeStatsResult } from '../schema/trade'; const RETRY_COUNT = 3; +const RETRY_LIMIT_DELAY = 100; @Injectable({ providedIn: 'root' @@ -54,7 +55,14 @@ export class TradeHttpService { query: queryId } }) - }).pipe(retry(RETRY_COUNT)); + }).pipe(retryWhen(errors => errors.pipe( + flatMap((error: HttpErrorResponse) => { + if (error.status === 429) { + return of(error).pipe(delay(RETRY_LIMIT_DELAY)); + } + return throwError(error); + }) + ))); } private getApiUrl(postfix: string, language: Language): string { diff --git a/src/app/layout/page/overlay/overlay.component.ts b/src/app/layout/page/overlay/overlay.component.ts index ef13ec32..9df440ed 100644 --- a/src/app/layout/page/overlay/overlay.component.ts +++ b/src/app/layout/page/overlay/overlay.component.ts @@ -8,6 +8,7 @@ import { TranslateService } from '@ngx-translate/core'; import { ContextService } from '@shared/module/poe/service'; import { Context, Language } from '@shared/module/poe/type'; import { Observable } from 'rxjs'; +import { delay, distinctUntilChanged, filter, map } from 'rxjs/operators'; import { version } from '../../../../../package.json'; import { UserSettingsService } from '../../service/user-settings.service'; import { UserSettings } from '../../type'; @@ -45,7 +46,6 @@ export class OverlayComponent implements OnInit, OnDestroy { } public ngOnInit(): void { - this.registerAutoHide(); this.checkVersion(); this.initSettings(); } @@ -54,50 +54,80 @@ export class OverlayComponent implements OnInit, OnDestroy { this.unregisterShortcuts(); } + private checkVersion(): void { + this.releasesHttpService.getLatestRelease().subscribe(release => { + if (release && release.tag_name !== version && release.assets && release.assets[0].browser_download_url) { + if (confirm(`A new version: '${release.tag_name}' is available. Go to download Page?`)) { + this.browser.open(release.html_url); + } + } + }); + } + private initSettings(): void { this.userSettingsService.init(this.modules).subscribe(settings => { this.translate.use(`${settings.language}`); this.context.init(this.getContext(settings)); - this.registerShortcuts(settings); + this.registerVisibleChange(); this.renderer.on('show-user-settings').subscribe(() => { this.openUserSettings(); }); }); } - private registerShortcuts(settings: UserSettings): void { - this.registerFeatures(settings); - this.registerSettings(settings); - this.registerExit(settings); - this.dialogs.registerShortcuts(); - } + private registerVisibleChange(): void { + this.app.visibleChange().pipe( + map(flag => { + if (flag === VisibleFlag.None) { + this.window.hide(); + } else { + this.window.show(); + } - private checkVersion(): void { - this.releasesHttpService.getLatestRelease().subscribe(release => { - if (release && release.tag_name !== version && release.assets && release.assets[0].browser_download_url) { - if (confirm(`A new version: '${release.tag_name}' is available. Go to download Page?`)) { - this.browser.open(release.html_url); + const visible = (flag & VisibleFlag.Game) === VisibleFlag.Game; + if (!visible) { + this.unregisterShortcuts(); } - } + return visible; + }), + distinctUntilChanged(), + filter(x => x), + delay(500) + ).subscribe(() => { + this.registerShortcuts(); }); } - private registerAutoHide(): void { - this.app.visibleChange().subscribe(flag => { - if (flag === VisibleFlag.None) { - this.window.hide(); - } else { - this.window.show(); - } + private openUserSettings(): void { + if (!this.userSettingsOpen) { + this.unregisterShortcuts(); + this.userSettingsOpen = this.renderer.open('user-settings'); - if ((flag & VisibleFlag.Game) !== VisibleFlag.Game) { - this.dialogs.unregisterShortcuts(); - } else { - this.dialogs.registerShortcuts(); - } + this.userSettingsOpen.subscribe(() => { + this.userSettingsOpen = null; + this.userSettingsService.get().subscribe(settings => { + this.translate.use(`${settings.language}`); + this.context.update(this.getContext(settings)); + this.registerShortcuts(); + }); + }, () => this.userSettingsOpen = null); + } + } + + private registerShortcuts(): void { + this.userSettingsService.get().subscribe(settings => { + this.registerFeatures(settings); + this.registerSettings(settings); + this.registerExit(settings); + this.dialogs.registerShortcuts(); }); } + private unregisterShortcuts(): void { + this.shortcut.unregisterAll(); + this.dialogs.unregisterShortcuts(); + } + private registerFeatures(settings: UserSettings): void { this.modules.forEach(mod => { const features = mod.getFeatures(settings); @@ -123,26 +153,6 @@ export class OverlayComponent implements OnInit, OnDestroy { } } - private unregisterShortcuts(): void { - this.shortcut.unregisterAll(); - } - - private openUserSettings(): void { - if (!this.userSettingsOpen) { - this.unregisterShortcuts(); - this.userSettingsOpen = this.renderer.open('user-settings'); - - this.userSettingsOpen.subscribe(() => { - this.userSettingsOpen = null; - this.userSettingsService.get().subscribe(settings => { - this.translate.use(`${settings.language}`); - this.context.update(this.getContext(settings)); - this.registerShortcuts(settings); - }); - }, () => this.userSettingsOpen = null); - } - } - private getContext(settings: UserSettings): Context { const context: Context = { language: settings.language, diff --git a/src/app/modules/command/service/command.service.ts b/src/app/modules/command/service/command.service.ts index cc98ef6e..be8b47f5 100644 --- a/src/app/modules/command/service/command.service.ts +++ b/src/app/modules/command/service/command.service.ts @@ -21,7 +21,7 @@ export class CommandService { private init(): void { this.command$.pipe( - throttleTime(150), + throttleTime(350), map(command => { const text = this.clipboard.readText(); this.clipboard.writeText(command); @@ -31,7 +31,7 @@ export class CommandService { this.keyboard.keyTap('enter'); return text; }), - delay(50), + delay(200), tap(text => { this.clipboard.writeText(text); }) diff --git a/src/app/modules/evaluate/component/evaluate/evaluate.component.scss b/src/app/modules/evaluate/component/evaluate/evaluate.component.scss index 96cf3cad..81cb0546 100644 --- a/src/app/modules/evaluate/component/evaluate/evaluate.component.scss +++ b/src/app/modules/evaluate/component/evaluate/evaluate.component.scss @@ -3,6 +3,7 @@ align-items: center; justify-content: center; overflow: hidden; + overscroll-behavior: none; padding-left: 60px; max-width: 340px; margin: 0 auto; diff --git a/src/app/shared/module/poe/component/item-frame-header/item-frame-header.component.scss b/src/app/shared/module/poe/component/item-frame-header/item-frame-header.component.scss index 98f9668c..4d48c330 100644 --- a/src/app/shared/module/poe/component/item-frame-header/item-frame-header.component.scss +++ b/src/app/shared/module/poe/component/item-frame-header/item-frame-header.component.scss @@ -79,6 +79,16 @@ } } + &.divinationcard { + background: url(../../../../../../assets/poe/item/header-card-left.png) top left no-repeat, + url(../../../../../../assets/poe/item/header-card-right.png) top right no-repeat, + url(../../../../../../assets/poe/item/header-card-middle.png) top center repeat-x; + + > .name { + color: #000; + } + } + &.gem { background: url(../../../../../../assets/poe/item/header-gem-left.png) top left no-repeat, url(../../../../../../assets/poe/item/header-gem-right.png) top right no-repeat, diff --git a/src/app/shared/module/poe/config/pseudo.config.ts b/src/app/shared/module/poe/config/pseudo.config.ts index 693ae4cc..6c261ea3 100644 --- a/src/app/shared/module/poe/config/pseudo.config.ts +++ b/src/app/shared/module/poe/config/pseudo.config.ts @@ -10,6 +10,7 @@ export enum ModifierType { export interface Modifier { id: string; type: ModifierType; + count?: number; } export interface PseudoModifier { @@ -58,30 +59,27 @@ export const PSEUDO_MODIFIERS: { }, pseudo_total_strength: { mods: [ - { id: 'additional_strength', type: ModifierType.Addition }, - { id: 'additional_strength_and_dexterity', type: ModifierType.Addition }, - { id: 'additional_strength_and_intelligence', type: ModifierType.Addition }, - { id: 'additional_all_attributes', type: ModifierType.Addition }, - ], - count: 2 + { id: 'additional_strength', type: ModifierType.Addition, count: 1 }, + { id: 'additional_strength_and_dexterity', type: ModifierType.Addition, count: 2 }, + { id: 'additional_strength_and_intelligence', type: ModifierType.Addition, count: 2 }, + { id: 'additional_all_attributes', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_dexterity: { mods: [ - { id: 'additional_dexterity', type: ModifierType.Addition }, - { id: 'additional_strength_and_dexterity', type: ModifierType.Addition }, - { id: 'additional_dexterity_and_intelligence', type: ModifierType.Addition }, - { id: 'additional_all_attributes', type: ModifierType.Addition }, - ], - count: 2 + { id: 'additional_dexterity', type: ModifierType.Addition, count: 1 }, + { id: 'additional_strength_and_dexterity', type: ModifierType.Addition, count: 2 }, + { id: 'additional_dexterity_and_intelligence', type: ModifierType.Addition, count: 2 }, + { id: 'additional_all_attributes', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_intelligence: { mods: [ - { id: 'additional_intelligence', type: ModifierType.Addition }, - { id: 'additional_strength_and_intelligence', type: ModifierType.Addition }, - { id: 'additional_dexterity_and_intelligence', type: ModifierType.Addition }, - { id: 'additional_all_attributes', type: ModifierType.Addition }, - ], - count: 2 + { id: 'additional_intelligence', type: ModifierType.Addition, count: 1 }, + { id: 'additional_strength_and_intelligence', type: ModifierType.Addition, count: 2 }, + { id: 'additional_dexterity_and_intelligence', type: ModifierType.Addition, count: 2 }, + { id: 'additional_all_attributes', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_all_attributes: { mods: [ @@ -117,33 +115,30 @@ export const PSEUDO_MODIFIERS: { }, pseudo_total_fire_resistance: { mods: [ - { id: 'base_fire_damage_resistance_%', type: ModifierType.Addition }, - { id: 'base_resist_all_elements_%', type: ModifierType.Addition }, - { id: 'fire_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'fire_and_cold_damage_resistance_%', type: ModifierType.Addition }, - { id: 'fire_and_lightning_damage_resistance_%', type: ModifierType.Addition }, - ], - count: 2 + { id: 'base_fire_damage_resistance_%', type: ModifierType.Addition, count: 1 }, + { id: 'base_resist_all_elements_%', type: ModifierType.Addition, count: 2 }, + { id: 'fire_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'fire_and_cold_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'fire_and_lightning_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_lightning_resistance: { mods: [ - { id: 'base_lightning_damage_resistance_%', type: ModifierType.Addition }, - { id: 'base_resist_all_elements_%', type: ModifierType.Addition }, - { id: 'lightning_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'fire_and_lightning_damage_resistance_%', type: ModifierType.Addition }, - { id: 'cold_and_lightning_damage_resistance_%', type: ModifierType.Addition }, - ], - count: 2 + { id: 'base_lightning_damage_resistance_%', type: ModifierType.Addition, count: 1 }, + { id: 'base_resist_all_elements_%', type: ModifierType.Addition, count: 2 }, + { id: 'lightning_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'fire_and_lightning_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'cold_and_lightning_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_cold_resistance: { mods: [ - { id: 'base_cold_damage_resistance_%', type: ModifierType.Addition }, - { id: 'base_resist_all_elements_%', type: ModifierType.Addition }, - { id: 'cold_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'fire_and_cold_damage_resistance_%', type: ModifierType.Addition }, - { id: 'cold_and_lightning_damage_resistance_%', type: ModifierType.Addition }, - ], - count: 2 + { id: 'base_cold_damage_resistance_%', type: ModifierType.Addition, count: 1 }, + { id: 'base_resist_all_elements_%', type: ModifierType.Addition, count: 2 }, + { id: 'cold_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'fire_and_cold_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'cold_and_lightning_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_elemental_resistance: { mods: [ @@ -162,12 +157,11 @@ export const PSEUDO_MODIFIERS: { }, pseudo_total_chaos_resistance: { mods: [ - { id: 'base_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'fire_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'lightning_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - { id: 'cold_and_chaos_damage_resistance_%', type: ModifierType.Addition }, - ], - count: 2 + { id: 'base_chaos_damage_resistance_%', type: ModifierType.Addition, count: 1 }, + { id: 'fire_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'lightning_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + { id: 'cold_and_chaos_damage_resistance_%', type: ModifierType.Addition, count: 2 }, + ] }, pseudo_total_resistance: { mods: [ diff --git a/src/app/shared/module/poe/service/item/item-evaluate.service.ts b/src/app/shared/module/poe/service/item/item-evaluate.service.ts index c3527d3d..6b343e9d 100644 --- a/src/app/shared/module/poe/service/item/item-evaluate.service.ts +++ b/src/app/shared/module/poe/service/item/item-evaluate.service.ts @@ -73,10 +73,14 @@ export class ItemEvaluateService { }); const filterLinks = (x: ItemCategoryValue) => { + if (x.links === undefined) { + return true; + } + if (links > 4) { return x.links === links; } - if (links > 0) { + if (links >= 0) { return x.links === 0; } return true; diff --git a/src/app/shared/module/poe/service/item/parser/item-post-parser-pseudo.service.ts b/src/app/shared/module/poe/service/item/parser/item-post-parser-pseudo.service.ts index 9695594b..b8f4955e 100644 --- a/src/app/shared/module/poe/service/item/parser/item-post-parser-pseudo.service.ts +++ b/src/app/shared/module/poe/service/item/parser/item-post-parser-pseudo.service.ts @@ -13,10 +13,11 @@ export class ItemPostParserPseudoService implements ItemPostParserService { const itemStats = [...item.stats]; Object.getOwnPropertyNames(PSEUDO_MODIFIERS).forEach(id => { + const pseudo = PSEUDO_MODIFIERS[id]; let values = []; let count = 0; + let minCount = pseudo.count; - const pseudo = PSEUDO_MODIFIERS[id]; if (pseudo.mods) { for (const mod of pseudo.mods) { const stats = itemStats.filter(x => x.id === mod.id && x.values.length > 0); @@ -27,9 +28,18 @@ export class ItemPostParserPseudoService implements ItemPostParserService { } continue; } + + if (mod.count && (!minCount || mod.count > minCount)) { + minCount = mod.count; + } + stats.forEach(stat => { ++count; values = this.calculateValue(stat, mod.type, values); + + if (stat.type !== StatType.Pseudo) { + item.stats = item.stats.filter(y => y !== stat); + } }); } } else if (pseudo.prop) { @@ -50,7 +60,7 @@ export class ItemPostParserPseudoService implements ItemPostParserService { mod: undefined }; itemStats.push(itemStat); - if (values.length > 0 && (!pseudo.count || count >= pseudo.count)) { + if (values.length > 0 && (!minCount || count >= minCount)) { item.stats.push(itemStat); } }); diff --git a/src/app/shared/module/poe/service/item/parser/item-section-properties-parser.service.ts b/src/app/shared/module/poe/service/item/parser/item-section-properties-parser.service.ts index e262fda3..5f109cfe 100644 --- a/src/app/shared/module/poe/service/item/parser/item-section-properties-parser.service.ts +++ b/src/app/shared/module/poe/service/item/parser/item-section-properties-parser.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { ExportedItem, Item, ItemProperties, ItemProperty, ItemSection, ItemSectionParserService, Section, ItemValueProperty } from '@shared/module/poe/type'; +import { ExportedItem, Item, ItemProperties, ItemProperty, ItemRarity, ItemSection, ItemSectionParserService, ItemValueProperty, Section } from '@shared/module/poe/type'; import { ClientStringService } from '../../client-string/client-string.service'; const AUGMENTED_PHRASE = ' (augmented)'; @@ -14,8 +14,11 @@ export class ItemSectionPropertiesParserService implements ItemSectionParserServ public section = ItemSection.Properties; public parse(item: ExportedItem, target: Item): Section { - const phrases = this.getPhrases(); + if (target.rarity === ItemRarity.DivinationCard) { + return null; + } + const phrases = this.getPhrases(); const propertiesSection = item.sections.find(section => phrases .findIndex(prop => section.content.indexOf(prop) !== -1) !== -1); if (!propertiesSection) { @@ -125,6 +128,7 @@ export class ItemSectionPropertiesParserService implements ItemSectionParserServ `${this.clientString.translate('Quality5')}: `, `${this.clientString.translate('Quality6')}: `, `${this.clientString.translate('Quality7')}: `, + `${this.clientString.translate('ItemDisplayStackSize')}: ` ]; } } diff --git a/src/assets/poe/item/header-card-left.png b/src/assets/poe/item/header-card-left.png new file mode 100644 index 0000000000000000000000000000000000000000..037b1f9c0fa4ca30abf4357839ad07892ca272c4 GIT binary patch literal 1212 zcmV;t1Vj6YP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1W`#uK~zXfRhChU z%j{KLP#;7T6=hdgSrrvT1m6U~NB^pSNKkZcZqi9SUsZZ%?Yp(< zB;8e~PMzvZ`s(RN+tp#PWm#=r7VC1hl+2Q@Rrj`TR=Q&Ax*B8EJwr>he)Vh4$;-oIK>%PHmPr(9Rf=f3V8kb~~@c+*ukx~`kB z?uha<&)S&n`ub?c@wUPfC__8nNvdMuT}#rAn^r^RwadP0ZFmWlV!*SVpJuEa-|m}&~)Ryr?JWrXrdVZmq1=x zbS-8^bNFJ?l+``mP46i{6Q&nK24^77l+JV4hDi`F@B%-(0iRgjpt6V?yx_!pPU!Qb zrUkP17m=C2V#%+hgJ^XY;RbX`)p9zhC~V?<)5)j}dg44$c8=G8uV*st^&z*O!LseC zJK@q1dWj*gisF4%uzS*(yKZp2rw1jpj~}_R%u&f9Pl}$3e$apvsswg#L=OZ`18d=F z=PvVr+(-2q=DA9`jI1}=`%O*Egzv+mANT4@`s1ejOz$z3aZzh zg%d7wLGpzi)tsD3RZSeq4i1775D-vbT?K4k5l&Hz<5-9|W~-~Y?x$fp+;Gaf&`PYE zbqHb=+pCBPQIvMnmxOEUo#28DscNedNJEG(#i-!y%dQ#01`#C(O^brHervtQ=W85C zyE~ut85`|NWDn)e6rdXg;$)cjOI9f`Sj!MwX4AuLNB%9i1=w2 z3mJa!$*3Z26$hLP!qSi5z4(L0l0jC)PX39K1y_HXAi_avH literal 0 HcmV?d00001 diff --git a/src/assets/poe/item/header-card-middle.png b/src/assets/poe/item/header-card-middle.png new file mode 100644 index 0000000000000000000000000000000000000000..d41361f6b1d92686e425a61871bb0189bbc69158 GIT binary patch literal 1111 zcmV-d1gQIoP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1MEpeK~zXfU6wnN z6fqD)CG}@Ec6SJ_L0~Nr7z7qBE(RA^11^9=;Njw6a|o`)CH6D@5&5ztW&_RCNG+AJ zs@YdvJ}uB#v$dLZEe@Hh6Z;Ns6jwQ z)bj6N-#r4LWPu2uK(qT@ikfMF@xWebXlNtySR*{d3%M>3hc<`{c|*?}AOO$vAzfWv zOOEOC@|do#LypI1>G~yIKac`<(0>H3}29|j5Pray=js`NvV}|BF1(zh{zwC(j;#W@@|s1-XsI&XWs%8 zgU%fdH(3;U+q$H6JxNyA5GrI0?(lqWpyszFqI4@*@6tnaI5Mzpds+kv@VW`Sg*KGn z6)7goHc2>{QsK$cKo&K|Dh;auP^254swcEG717lVk~x9Tv&y z?nuhIke#!FtBZyLt$Co|cm}}6LON%$+7>s+Gl^1aKoLr-D^38tDTvUagms7Jf@(ze zLS$UE2Jq_agkYo{46Qf+F@_aL?pc5=oH5z1BVA&09e$9LIgIw&Bhwp>aK&yp+zEW!VhkOj-UkIimMe-2B>n3#offF zAoeNAGDJc%C*Mx9}b zag?fhNJd;}HpFEQ2Li!EaS@_A!w^PExkBO`IyCBtYcy`YNG)#u9Uj34T;O$~FUjFfulAu~yPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1XxK#K~zXfU6#GB z97PaDdwOPPE&JXCfyFBzA|nwXB2rQUUcdpo00|-^B_ZY^cnu_wkRU*a03#WRi)Dj< z?(WX?>~KzX&$UIbO5HPEUG>#hRXy9i|IS$#!>iPN{lzD% zhsI$Dg$@O^`=L)=*QGO_&pfjX<1sL*5z$@!{UrVH^KYs9_M0yQkp^;y5xg5{7xNjT zylDpOgMQFpInQ(YYj zcj!zQ%=`T<4(`&hGqizugj8nU?Zz>=e+v<;&_!dIhIWR(2xAvOS=2UYbh^!Xi_4im!1`UM0sc&q>6~G zyFyqZ9mj}bsN^bbt&(9y21VK0L$ncw`}}62dHnQ6`uF)!JzXjhL2U_OpUGro29y)& zohJlxBLVK87wQUB6#O)ol*?>(UMkeGb87Pqg38rRcI`EsiNST}j~@povcGy~wq27z<9bUL-lLkJz9|(F(Goj=03| z7{!O!peOj6phTYJ(h>q;%SzNuy@MPoSrWm6q5oe%8eFlSY}&1E0{YrKG{UuM(<(J= z!{=G_NL+X;O6os!hXsc9g;e$pDIjCCqJ-oSpQ~&i z35!u(Ln?$gnYHci4dNo^O}Mx;?2l(_ZIa|hw8S6jwJ1#V$hx&)+%EEmo~nj@ zwph1cIKr{fxXy7s$Pp5U`PC73L5O@